import React, { useEffect, useMemo, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Button, Card, Col, Drawer, Form, Input, InputNumber, Popconfirm, Row, Select, Space, Table, Tag, Tooltip, Typography, message } from "antd";
import * as AntIcons from "@ant-design/icons";
import { CheckSquareOutlined, ClusterOutlined, DeleteOutlined, EditOutlined, FolderOutlined, InfoCircleOutlined, MenuOutlined, PlusOutlined, ReloadOutlined, SearchOutlined } from "@ant-design/icons";
import { createPermission, deletePermission, listMyPermissions, updatePermission } from "@/api";
import { useDict } from "@/hooks/useDict";
import { usePermission } from "@/hooks/usePermission";
import PageHeader from "@/components/shared/PageHeader";
import type { SysPermission } from "@/types";
import "./index.less";

const { Text } = Typography;
type TreePermission = SysPermission & { key: number; children?: TreePermission[] };

const legacyIconAliases: Record<string, string> = {
  dashboard: "DashboardOutlined",
  meeting: "VideoCameraOutlined",
  user: "UserOutlined",
  role: "TeamOutlined",
  permission: "SafetyCertificateOutlined",
  device: "DesktopOutlined",
  tenant: "ShopOutlined",
  org: "ApartmentOutlined",
  dict: "BookOutlined",
  setting: "SettingOutlined"
};

const menuIconOptions = Object.keys(AntIcons)
  .filter((key) => /(?:Outlined|Filled|TwoTone)$/.test(key))
  .sort((left, right) => left.localeCompare(right));

function renderSelectableIcon(iconName?: string) {
  const resolvedName = iconName ? (legacyIconAliases[iconName] || iconName) : undefined;
  if (!resolvedName) return null;
  const iconsMap = AntIcons as unknown as Record<string, React.ComponentType<{ className?: string; style?: React.CSSProperties }>>;
  const IconComponent = iconsMap[resolvedName];
  return IconComponent ? <IconComponent aria-hidden="true" /> : null;
}

function buildTree(list: SysPermission[]): TreePermission[] {
  const map = new Map<number, TreePermission>();
  const roots: TreePermission[] = [];

  (list || []).forEach((item) => {
    map.set(item.permId, { ...item, key: item.permId, children: [] });
  });

  map.forEach((node) => {
    if (node.parentId && map.has(node.parentId)) {
      map.get(node.parentId)!.children!.push(node);
    } else {
      roots.push(node);
    }
  });

  const sortChildren = (nodes: TreePermission[]) => {
    nodes.sort((left, right) => (left.sortOrder || 0) - (right.sortOrder || 0));
    nodes.forEach((node) => node.children && sortChildren(node.children));
  };

  sortChildren(roots);
  return roots;
}

export default function Permissions() {
  const { t } = useTranslation();
  const { can } = usePermission();
  const { items: statusDict } = useDict("sys_common_status");
  const { items: typeDict } = useDict("sys_permission_type");
  const { items: visibleDict } = useDict("sys_common_visibility");
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [data, setData] = useState<SysPermission[]>([]);
  const [query, setQuery] = useState({ name: "", code: "", permType: "" });
  const [open, setOpen] = useState(false);
  const [editing, setEditing] = useState<SysPermission | null>(null);
  const [iconSearchKeyword, setIconSearchKeyword] = useState("");
  const [iconPickerOpen, setIconPickerOpen] = useState(false);
  const [visibleIconCount, setVisibleIconCount] = useState(120);
  const iconGridRef = useRef<HTMLDivElement | null>(null);
  const [form] = Form.useForm();

  const load = async () => {
    setLoading(true);
    try {
      const list = await listMyPermissions();
      setData(list || []);
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    load();
  }, []);

  const filtered = useMemo(() => {
    return data.filter((permission) => {
      const hitName = query.name ? permission.name?.includes(query.name) : true;
      const hitCode = query.code ? permission.code?.includes(query.code) : true;
      const hitType = query.permType ? permission.permType === query.permType : true;
      return hitName && hitCode && hitType;
    });
  }, [data, query]);

  const treeData = useMemo(() => buildTree(filtered), [filtered]);
  const currentPermType = Form.useWatch("permType", form);
  const selectedIcon = Form.useWatch("icon", form);

  const parentOptions = useMemo(() => {
    return data
      .filter((permission) => (currentPermType === "button" ? permission.permType === "menu" : permission.permType === "directory"))
      .map((permission) => ({ value: permission.permId, label: permission.name }));
  }, [data, currentPermType]);

  const filteredIconOptions = useMemo(() => {
    const keyword = iconSearchKeyword.trim().toLowerCase();
    if (!keyword) return menuIconOptions;
    return menuIconOptions.filter((iconName) => iconName.toLowerCase().includes(keyword));
  }, [iconSearchKeyword]);

  const visibleIconOptions = useMemo(() => filteredIconOptions.slice(0, visibleIconCount), [filteredIconOptions, visibleIconCount]);

  useEffect(() => {
    setVisibleIconCount(120);
  }, [iconSearchKeyword, iconPickerOpen]);

  useEffect(() => {
    if (!iconPickerOpen || !selectedIcon || iconSearchKeyword.trim()) return;
    const selectedIndex = filteredIconOptions.findIndex((iconName) => iconName === selectedIcon);
    if (selectedIndex >= 0 && selectedIndex + 24 > visibleIconCount) {
      setVisibleIconCount(Math.min(selectedIndex + 60, filteredIconOptions.length));
      return;
    }
    const timer = window.setTimeout(() => {
      const selectedNode = iconGridRef.current?.querySelector(`[data-icon-name="${selectedIcon}"]`) as HTMLButtonElement | null;
      selectedNode?.scrollIntoView({ block: "nearest", inline: "nearest" });
    }, 0);
    return () => window.clearTimeout(timer);
  }, [filteredIconOptions, iconPickerOpen, iconSearchKeyword, selectedIcon, visibleIconCount]);

  const clearSelectedIcon = () => {
    form.setFieldValue("icon", undefined);
    setIconSearchKeyword("");
  };

  const openCreate = () => {
    setEditing(null);
    form.resetFields();
    setIconSearchKeyword("");
    setIconPickerOpen(false);
    form.setFieldsValue({ level: 1, permType: "directory", status: 1, isVisible: 1, sortOrder: 0 });
    setOpen(true);
  };

  const openEdit = (record: SysPermission) => {
    setEditing(record);
    setIconSearchKeyword(record.icon || "");
    setIconPickerOpen(false);
    form.setFieldsValue(record);
    setOpen(true);
  };

  const openAddChild = (record: SysPermission) => {
    setEditing(null);
    form.resetFields();
    setIconSearchKeyword("");
    setIconPickerOpen(false);
    const parentLevel = record.level || 1;
    const newLevel = Math.min(parentLevel + 1, 3);
    let defaultType = "menu";
    if (newLevel === 3) defaultType = "button";
    if (newLevel === 1) defaultType = "directory";
    form.setFieldsValue({ parentId: record.permId, level: newLevel, permType: defaultType, status: 1, isVisible: 1, sortOrder: 0 });
    setOpen(true);
  };

  const submit = async () => {
    const values = await form.validateFields();
    setSaving(true);
    try {
      let calculatedLevel = 1;
      if (values.parentId) {
        const parent = data.find((permission) => permission.permId === values.parentId);
        if (parent) calculatedLevel = (parent.level || 1) + 1;
      }

      const payload: Partial<SysPermission> = {
        parentId: values.parentId || 0,
        name: values.name,
        code: values.code,
        permType: values.permType,
        level: calculatedLevel,
        path: values.path,
        component: values.component,
        icon: values.icon,
        sortOrder: values.sortOrder,
        isVisible: values.isVisible,
        status: values.status,
        description: values.description
      };

      if (editing) {
        await updatePermission(editing.permId, payload);
      } else {
        await createPermission(payload);
      }

      message.success(t("common.success"));
      setOpen(false);
      load();
    } finally {
      setSaving(false);
    }
  };

  const remove = async (id: number) => {
    await deletePermission(id);
    message.success(t("common.success"));
    load();
  };

  const columns = [
    {
      title: t("permissions.permName"),
      dataIndex: "name",
      key: "name",
      render: (text: string, record: TreePermission) => {
        let icon = <CheckSquareOutlined style={{ color: "#52c41a" }} aria-hidden="true" />;
        if (record.permType === "directory") icon = <FolderOutlined style={{ color: "#faad14" }} aria-hidden="true" />;
        if (record.permType === "menu") icon = <MenuOutlined style={{ color: "#1890ff" }} aria-hidden="true" />;
        return <Space>{icon}<Text strong={record.level === 1}>{text}</Text></Space>;
      }
    },
    {
      title: t("permissions.permCode"),
      dataIndex: "code",
      key: "code",
      render: (text: string) => text ? <Tag color="blue" className="tabular-nums">{text}</Tag> : "-"
    },
    {
      title: t("permissions.permType"),
      dataIndex: "permType",
      width: 90,
      render: (type: string) => {
        const item = typeDict.find((dictItem) => dictItem.itemValue === type);
        let color: "warning" | "default" | "processing" = "warning";
        if (type === "directory") color = "default";
        if (type === "menu") color = "processing";
        return <Tag color={color}>{item ? item.itemLabel : type}</Tag>;
      }
    },
    { title: t("permissions.sort"), dataIndex: "sortOrder", width: 80, className: "tabular-nums" },
    {
      title: t("permissions.route"),
      key: "route",
      ellipsis: true,
      render: (_: unknown, record: TreePermission) => (
        <div className="flex flex-col">
          {record.path && <Text type="secondary" style={{ fontSize: "12px" }} className="tabular-nums">{record.path}</Text>}
          {record.component && <Text type="secondary" style={{ fontSize: "11px" }}>{record.component}</Text>}
        </div>
      )
    },
    {
      title: t("permissions.visible"),
      dataIndex: "isVisible",
      width: 80,
      render: (value: number) => {
        const item = visibleDict.find((dictItem) => dictItem.itemValue === String(value));
        return value === 1 ? <Tag color="blue">{item?.itemLabel || t("permissionsExt.visible")}</Tag> : <Tag>{item?.itemLabel || t("permissionsExt.hidden")}</Tag>;
      }
    },
    {
      title: t("common.status"),
      dataIndex: "status",
      width: 80,
      render: (value: number) => {
        const item = statusDict.find((dictItem) => dictItem.itemValue === String(value));
        return value === 1 ? <Tag color="green">{item?.itemLabel || t("permissionsExt.enabled")}</Tag> : <Tag color="red">{item?.itemLabel || t("permissionsExt.disabled")}</Tag>;
      }
    },
    {
      title: t("common.action"),
      width: 150,
      fixed: "right" as const,
      render: (_: unknown, record: TreePermission) => (
        <Space>
          {can("sys:permission:create") && record.permType !== "button" && <Tooltip title={t("permissionsExt.addChild")}><Button type="text" size="small" icon={<PlusOutlined aria-hidden="true" />} onClick={() => openAddChild(record)} aria-label={t("permissionsExt.addChild")} /></Tooltip>}
          {can("sys:permission:update") && <Button type="text" size="small" icon={<EditOutlined aria-hidden="true" />} onClick={() => openEdit(record)} aria-label={t("common.edit")} />}
          {can("sys:permission:delete") && <Popconfirm title={t("permissionsExt.deleteConfirm", { name: record.name })} okText={t("common.confirm")} cancelText={t("common.cancel")} onConfirm={() => remove(record.permId)}><Button type="text" size="small" danger icon={<DeleteOutlined aria-hidden="true" />} aria-label={t("common.delete")} /></Popconfirm>}
        </Space>
      )
    }
  ];

  return (
    <div className="app-page permissions-page">
      <PageHeader title={t("permissions.title")} subtitle={t("permissions.subtitle")} />

      <Card className="app-page__filter-card" styles={{ body: { padding: "16px" } }}>
        <Space wrap size="middle" className="app-page__toolbar" style={{ justifyContent: "space-between", width: "100%" }}>
          <Space wrap size="middle" className="app-page__toolbar">
          <Input placeholder={t("permissions.permName")} value={query.name} onChange={(event) => setQuery({ ...query, name: event.target.value })} prefix={<SearchOutlined className="text-gray-400" aria-hidden="true" />} style={{ width: 180 }} allowClear aria-label={t("permissions.permName")} />
          <Input placeholder={t("permissions.permCode")} value={query.code} onChange={(event) => setQuery({ ...query, code: event.target.value })} style={{ width: 180 }} allowClear aria-label={t("permissions.permCode")} />
          <Select placeholder={t("permissions.permType")} allowClear value={query.permType || undefined} onChange={(value) => setQuery({ ...query, permType: value || "" })} options={typeDict.map((item) => ({ value: item.itemValue, label: item.itemLabel }))} style={{ width: 120 }} aria-label={t("permissions.permType")} />
          <Button type="primary" icon={<SearchOutlined aria-hidden="true" />} onClick={load}>{t("common.search")}</Button>
          <Button icon={<ReloadOutlined aria-hidden="true" />} onClick={() => setQuery({ name: "", code: "", permType: "" })}>{t("common.reset")}</Button>
          </Space>
          {can("sys:permission:create") && <Button type="primary" icon={<PlusOutlined aria-hidden="true" />} onClick={openCreate}>{t("common.create")}</Button>}
        </Space>
      </Card>

      <Card className="app-page__content-card permissions-content-card flex-1 flex flex-col overflow-hidden" styles={{ body: { padding: 0, flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" } }}>
        <Table className="permissions-table-full" rowKey="permId" loading={loading} dataSource={treeData} columns={columns} pagination={false} size="middle" scroll={{ x: 'max-content', y: '100%' }} expandable={{ defaultExpandAllRows: false, rowExpandable: (record) => record.permType !== "button" && !!record.children?.length }} />
      </Card>

      <Drawer title={<Space><ClusterOutlined aria-hidden="true" /><span>{editing ? t("permissions.drawerTitleEdit") : t("permissions.drawerTitleCreate")}</span></Space>} open={open} onClose={() => setOpen(false)} width={520} destroyOnClose footer={<div className="app-page__drawer-footer"><Button onClick={() => setOpen(false)}>{t("common.cancel")}</Button><Button type="primary" loading={saving} onClick={submit}>{t("common.save")}</Button></div>}>
        <Form form={form} layout="vertical" className="permission-form" onValuesChange={(changed) => changed.permType === "button" && form.setFieldsValue({ isVisible: 0 })}>
          <Row gutter={16}>
            <Col span={24}>
              <Form.Item label={t("permissions.permType")} name="permType" rules={[{ required: true }]}>
                <Select options={typeDict.map((item) => ({ value: item.itemValue, label: item.itemLabel }))} aria-label={t("permissions.permType")} />
              </Form.Item>
            </Col>
          </Row>
          <Form.Item label={t("permissions.parentId")} name="parentId">
            <Select allowClear showSearch placeholder={t("permissionsExt.parentPlaceholder")} options={parentOptions} aria-label={t("permissions.parentId")} />
          </Form.Item>
          <Form.Item label={t("permissions.permName")} name="name" rules={[{ required: true, message: t("permissions.permName") }]}>
            <Input placeholder={t("permissionsExt.namePlaceholder")} />
          </Form.Item>
          <Form.Item label={<Space><span>{t("permissions.permCode")}</span><Tooltip title={t("permissionsExt.codeHelp")}><InfoCircleOutlined className="text-gray-400" /></Tooltip></Space>} name="code" rules={[{ required: true, message: t("permissions.permCode") }]}>
            <Input placeholder={t("permissionsExt.codePlaceholder")} className="tabular-nums" />
          </Form.Item>
          <Row gutter={16}>
            <Col span={12}>
              <Form.Item label={t("permissions.path")} name="path">
                <Input placeholder={t("permissionsExt.pathPlaceholder")} className="tabular-nums" />
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label={t("permissions.component")} name="component">
                <Input placeholder={t("permissionsExt.componentPlaceholder")} />
              </Form.Item>
            </Col>
          </Row>
          <Row gutter={16}>
            <Col span={24}>
              <Form.Item label={t("permissions.icon")}>
                <Form.Item name="icon" noStyle>
                  <Input type="hidden" />
                </Form.Item>
                <Space direction="vertical" size={12} style={{ width: "100%" }}>
                  <Space style={{ width: "100%", justifyContent: "space-between" }}>
                    <Input
                      readOnly
                      value={selectedIcon || ""}
                      onClick={() => {
                        setIconSearchKeyword("");
                        setIconPickerOpen(true);
                      }}
                      onFocus={() => {
                        setIconSearchKeyword("");
                        setIconPickerOpen(true);
                      }}
                      placeholder={t("permissionsExt.iconPlaceholder")}
                      prefix={renderSelectableIcon(selectedIcon) || <SearchOutlined aria-hidden="true" />}
                      style={{ width: 260 }}
                    />
                    <Space>
                      <Button size="small" onClick={() => {
                        if (!iconPickerOpen) {
                          setIconSearchKeyword("");
                        }
                        setIconPickerOpen((value) => !value);
                      }}>{iconPickerOpen ? t("permissionsExt.hideIconLibrary") : t("permissionsExt.showIconLibrary")}</Button>
                      {selectedIcon ? <Button size="small" onClick={clearSelectedIcon}>{t("common.reset")}</Button> : null}
                    </Space>
                  </Space>
                  {iconPickerOpen ? <div><Input value={iconSearchKeyword} onChange={(event) => setIconSearchKeyword(event.target.value)} placeholder={t("permissionsExt.iconSearchPlaceholder")} prefix={<SearchOutlined aria-hidden="true" />} allowClear style={{ marginBottom: 12 }} /><div ref={iconGridRef} onScroll={(event) => {
                    const target = event.currentTarget;
                    if (target.scrollTop + target.clientHeight >= target.scrollHeight - 48) {
                      setVisibleIconCount((count) => Math.min(count + 120, filteredIconOptions.length));
                    }
                  }} style={{ maxHeight: 240, overflowY: "auto", border: "1px solid #f0f0f0", borderRadius: 8, padding: 12, background: "#fafafa" }}>
                    <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(44px, 1fr))", gap: 10 }}>
                      {visibleIconOptions.map((iconName) => {
                        const active = selectedIcon === iconName;
                        return (
                          <Tooltip key={iconName} title={iconName}>
                            <Button
                              data-icon-name={iconName}
                              type="text"
                              onClick={() => {
                                const nextValue = active ? undefined : iconName;
                                form.setFieldValue("icon", nextValue);
                                if (nextValue) {
                                  setIconSearchKeyword("");
                                  setIconPickerOpen(false);
                                }
                              }}
                              aria-label={iconName}
                              style={{
                                height: 44,
                                width: "100%",
                                borderRadius: 10,
                                border: active ? "1px solid #1677ff" : "1px solid transparent",
                                background: active ? "#e6f4ff" : "#fff",
                                color: active ? "#1677ff" : "inherit",
                                display: "inline-flex",
                                alignItems: "center",
                                justifyContent: "center",
                                boxShadow: active ? "0 0 0 2px rgba(22,119,255,0.12)" : "none"
                              }}
                            >
                              {renderSelectableIcon(iconName)}
                            </Button>
                          </Tooltip>
                        );
                      })}
                    </div>
                    {!filteredIconOptions.length ? <div style={{ padding: "16px 0", textAlign: "center", color: "#8c8c8c" }}>{t("permissionsExt.iconEmpty")}</div> : null}
                    {visibleIconOptions.length < filteredIconOptions.length ? <div style={{ paddingTop: 12, textAlign: "center", color: "#8c8c8c", fontSize: 12 }}>{t("permissionsExt.iconLoadingMore", { current: visibleIconOptions.length, total: filteredIconOptions.length })}</div> : null}
                  </div></div> : null}
                </Space>
              </Form.Item>
            </Col>
          </Row>
          <Row gutter={16}>
            <Col span={12}>
              <Form.Item label={t("permissions.sort")} name="sortOrder" initialValue={0}>
                <InputNumber style={{ width: "100%" }} min={0} className="tabular-nums" />
              </Form.Item>
            </Col>
          </Row>
          <Row gutter={16}>
            <Col span={12}>
              <Form.Item label={t("permissions.isVisible")} name="isVisible" initialValue={1}>
                <Select options={visibleDict.map((item) => ({ value: Number(item.itemValue), label: item.itemLabel }))} />
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label={t("common.status")} name="status" initialValue={1}>
                <Select options={statusDict.map((item) => ({ value: Number(item.itemValue), label: item.itemLabel }))} />
              </Form.Item>
            </Col>
          </Row>
          <Form.Item label={t("permissions.description")} name="description">
            <Input.TextArea rows={2} placeholder={t("permissionsExt.descriptionPlaceholder")} />
          </Form.Item>
        </Form>
      </Drawer>
    </div>
  );
}