import { PlusOutlined } from '@ant-design/icons';
import { ProCard } from '@ant-design/pro-components';
import {
  App,
  Button,
  Col,
  Form,
  Input,
  InputNumber,
  Modal,
  Popconfirm,
  Radio,
  Row,
  Select,
  Space,
  Switch,
  Table,
  Tabs,
  Tree,
  Typography,
} from 'antd';
import type { ColumnsType } from 'antd/es/table';
import type { DataNode } from 'antd/es/tree';
import { useEffect, useMemo, useState } from 'react';

import {
  iconOptions,
  initialButtonPermissions,
  initialMenuTree,
  type ButtonPermissionItem,
  type MenuNodeType,
  type MenuPermissionNode,
} from './mock';

interface MenuFormValues {
  title: string;
  path: string;
  icon: string;
  order: number;
  type: MenuNodeType;
  visible: boolean;
  permission: string;
  remark?: string;
}

interface ButtonFormValues {
  name: string;
  code: string;
  menuKey: string;
}

const findNode = (nodes: MenuPermissionNode[], key: string): MenuPermissionNode | undefined => {
  for (const node of nodes) {
    if (node.key === key) return node;
    if (node.children) {
      const found = findNode(node.children, key);
      if (found) return found;
    }
  }
  return undefined;
};

const findParent = (
  nodes: MenuPermissionNode[],
  key: string,
  parent?: MenuPermissionNode,
): MenuPermissionNode | undefined => {
  for (const node of nodes) {
    if (node.key === key) return parent;
    if (node.children?.length) {
      const found = findParent(node.children, key, node);
      if (found !== undefined || node.children.some(child => child.key === key)) {
        return found ?? node;
      }
    }
  }
  return undefined;
};

const updateNode = (
  nodes: MenuPermissionNode[],
  key: string,
  updater: (node: MenuPermissionNode) => MenuPermissionNode,
): MenuPermissionNode[] =>
  nodes.map(node => {
    if (node.key === key) return updater(node);
    if (!node.children) return node;
    return { ...node, children: updateNode(node.children, key, updater) };
  });

const removeNode = (nodes: MenuPermissionNode[], key: string): MenuPermissionNode[] =>
  nodes
    .filter(node => node.key !== key)
    .map(node => (node.children ? { ...node, children: removeNode(node.children, key) } : node));

const collectNodeKeys = (node: MenuPermissionNode): string[] => [
  node.key,
  ...(node.children?.flatMap(collectNodeKeys) ?? []),
];

const toTreeData = (nodes: MenuPermissionNode[]): DataNode[] =>
  nodes.map(node => ({
    key: node.key,
    title: node.title,
    children: node.children ? toTreeData(node.children) : undefined,
  }));

const flattenMenus = (nodes: MenuPermissionNode[], parentTitle = ''): { key: string; label: string }[] => {
  const result: { key: string; label: string }[] = [];
  nodes.forEach(node => {
    const label = parentTitle ? `${parentTitle} / ${node.title}` : node.title;
    if (node.type === '菜单' || node.type === '目录') {
      result.push({ key: node.key, label });
    }
    if (node.children) result.push(...flattenMenus(node.children, label));
  });
  return result;
};

export default function PermissionManagement() {
  const { message } = App.useApp();
  const [menuForm] = Form.useForm<MenuFormValues>();
  const [buttonForm] = Form.useForm<ButtonFormValues>();
  const [menuTree, setMenuTree] = useState(initialMenuTree);
  const [buttons, setButtons] = useState(initialButtonPermissions);
  const [selectedKey, setSelectedKey] = useState('3-1');
  const [buttonOpen, setButtonOpen] = useState(false);
  const [editingButton, setEditingButton] = useState<ButtonPermissionItem>();
  const [activeTab, setActiveTab] = useState('menu');

  const selectedNode = useMemo(() => findNode(menuTree, selectedKey), [menuTree, selectedKey]);
  const menuOptions = useMemo(() => flattenMenus(menuTree), [menuTree]);

  const relatedButtons = useMemo(() => buttons.filter(item => item.menuKey === selectedKey), [buttons, selectedKey]);

  const syncForm = (node?: MenuPermissionNode) => {
    if (!node) return;
    menuForm.setFieldsValue({
      title: node.title,
      path: node.path,
      icon: node.icon,
      order: node.order,
      type: node.type,
      visible: node.visible,
      permission: node.permission,
      remark: node.remark ?? '',
    });
  };

  useEffect(() => {
    syncForm(selectedNode);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectedNode]);

  const selectMenu = (key: string) => {
    setSelectedKey(key);
  };

  const addSibling = () => {
    if (!selectedNode) {
      message.warning('请先选择菜单');
      return;
    }
    const parent = findParent(menuTree, selectedKey);
    const newNode: MenuPermissionNode = {
      key: `menu-${Date.now()}`,
      title: '新菜单',
      path: '/new',
      icon: 'AppstoreOutlined',
      order: 99,
      type: '菜单',
      visible: true,
      permission: 'new:view',
    };

    if (!parent) {
      setMenuTree(current => [...current, newNode]);
    } else {
      setMenuTree(current =>
        updateNode(current, parent.key, node => ({
          ...node,
          children: [...(node.children ?? []), newNode],
        })),
      );
    }
    setSelectedKey(newNode.key);
    syncForm(newNode);
    message.success('已新增同级菜单');
  };

  const addChild = () => {
    if (!selectedNode) {
      message.warning('请先选择菜单');
      return;
    }
    const newNode: MenuPermissionNode = {
      key: `menu-${Date.now()}`,
      title: '新子菜单',
      path: `${selectedNode.path}/child`,
      icon: 'AppstoreOutlined',
      order: (selectedNode.children?.length ?? 0) + 1,
      type: '菜单',
      visible: true,
      permission: `${selectedNode.permission}:child`,
    };
    setMenuTree(current =>
      updateNode(current, selectedKey, node => ({
        ...node,
        type: node.type === '菜单' ? '目录' : node.type,
        children: [...(node.children ?? []), newNode],
      })),
    );
    setSelectedKey(newNode.key);
    syncForm(newNode);
    message.success('已新增子级菜单');
  };

  const deleteMenu = () => {
    if (!selectedNode) return;
    const removedKeys = new Set(collectNodeKeys(selectedNode));
    const nextTree = removeNode(menuTree, selectedKey);
    setMenuTree(nextTree);
    setButtons(current => current.filter(item => !removedKeys.has(item.menuKey)));
    const fallback = nextTree[0]?.key ?? nextTree[0]?.children?.[0]?.key;
    if (fallback) {
      setSelectedKey(fallback);
      syncForm(findNode(nextTree, fallback));
    } else {
      setSelectedKey('');
      menuForm.resetFields();
    }
    message.success('菜单已删除');
  };

  const saveMenu = async () => {
    if (!selectedKey) return;
    const values = await menuForm.validateFields();
    const nextTree = updateNode(menuTree, selectedKey, node => ({
      ...node,
      ...values,
    }));
    const menuPaths = new Map(flattenMenus(nextTree).map(item => [item.key, item.label]));

    setMenuTree(nextTree);
    setButtons(current =>
      current.map(item => ({
        ...item,
        menuPath: menuPaths.get(item.menuKey) ?? item.menuPath,
      })),
    );
    message.success('菜单已保存');
  };

  const openCreateButton = () => {
    setEditingButton(undefined);
    buttonForm.setFieldsValue({
      name: '',
      code: '',
      menuKey: selectedKey || menuOptions[0]?.key,
    });
    setButtonOpen(true);
  };

  const openEditButton = (record: ButtonPermissionItem) => {
    setEditingButton(record);
    buttonForm.setFieldsValue({
      name: record.name,
      code: record.code,
      menuKey: record.menuKey,
    });
    setButtonOpen(true);
  };

  const saveButton = async () => {
    const values = await buttonForm.validateFields();
    const menuLabel = menuOptions.find(item => item.key === values.menuKey)?.label ?? '';
    if (editingButton) {
      setButtons(current =>
        current.map(item =>
          item.id === editingButton.id
            ? { ...item, name: values.name, code: values.code, menuKey: values.menuKey, menuPath: menuLabel }
            : item,
        ),
      );
      message.success('按钮权限已更新');
    } else {
      setButtons(current => [
        ...current,
        {
          id: `btn-${Date.now()}`,
          name: values.name,
          code: values.code,
          menuKey: values.menuKey,
          menuPath: menuLabel,
        },
      ]);
      message.success('按钮权限已添加');
    }
    setButtonOpen(false);
    buttonForm.resetFields();
  };

  const deleteButton = (record: ButtonPermissionItem) => {
    setButtons(current => current.filter(item => item.id !== record.id));
    message.success('按钮权限已删除');
  };

  const buttonColumns: ColumnsType<ButtonPermissionItem> = [
    { title: '权限名称', dataIndex: 'name', width: 120 },
    {
      title: '权限码',
      dataIndex: 'code',
      width: 220,
      render: (value: string) => <Typography.Text code>{value}</Typography.Text>,
    },
    { title: '所属菜单', dataIndex: 'menuPath', ellipsis: true },
    {
      title: '操作',
      key: 'actions',
      width: 140,
      render: (_, record) => (
        <Space size={2}>
          <Button type="link" size="small" onClick={() => openEditButton(record)}>
            编辑
          </Button>
          <Popconfirm title={`确定删除权限 ${record.code}？`} onConfirm={() => deleteButton(record)}>
            <Button type="link" danger size="small">
              删除
            </Button>
          </Popconfirm>
        </Space>
      ),
    },
  ];

  const menuTab = (
    <Row gutter={16}>
      <Col xs={24} lg={8}>
        <ProCard
          title="菜单树"
          size="small"
          variant="outlined"
          extra={
            <Space size={4}>
              <Button size="small" type="link" onClick={addSibling}>
                + 新增同级
              </Button>
              <Button size="small" type="link" onClick={addChild}>
                + 新增子级
              </Button>
              <Popconfirm title="确定删除选中菜单？" disabled={!selectedKey} onConfirm={deleteMenu}>
                <Button size="small" type="link" danger disabled={!selectedKey}>
                  删除
                </Button>
              </Popconfirm>
            </Space>
          }
        >
          <Tree
            defaultExpandAll
            selectedKeys={selectedKey ? [selectedKey] : []}
            treeData={toTreeData(menuTree)}
            onSelect={keys => {
              if (keys[0]) selectMenu(String(keys[0]));
            }}
          />
        </ProCard>
      </Col>
      <Col xs={24} lg={16}>
        <ProCard title="菜单详情" size="small" variant="outlined">
          <Form form={menuForm} layout="vertical" requiredMark="optional" disabled={!selectedKey}>
            <Row gutter={16}>
              <Col span={12}>
                <Form.Item label="菜单名称" name="title" rules={[{ required: true, message: '请输入菜单名称' }]}>
                  <Input placeholder="例如 用户管理" />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="路由路径" name="path" rules={[{ required: true, message: '请输入路由路径' }]}>
                  <Input placeholder="/system/user" />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="图标" name="icon">
                  <Select options={iconOptions.map(value => ({ label: value, value }))} />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="排序" name="order" rules={[{ required: true }]}>
                  <InputNumber min={1} style={{ width: '100%' }} />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="类型" name="type" rules={[{ required: true }]}>
                  <Radio.Group
                    options={[
                      { label: '目录', value: '目录' },
                      { label: '菜单', value: '菜单' },
                      { label: '按钮', value: '按钮' },
                    ]}
                  />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="是否显示" name="visible" valuePropName="checked">
                  <Switch checkedChildren="显示" unCheckedChildren="隐藏" />
                </Form.Item>
              </Col>
              <Col span={12}>
                <Form.Item label="权限标识" name="permission" rules={[{ required: true, message: '请输入权限标识' }]}>
                  <Input placeholder="system:user:view" />
                </Form.Item>
              </Col>
              <Col span={24}>
                <Form.Item label="备注" name="remark">
                  <Input.TextArea rows={2} maxLength={200} showCount placeholder="请输入备注" />
                </Form.Item>
              </Col>
            </Row>
            <Button type="primary" onClick={saveMenu} disabled={!selectedKey}>
              保存
            </Button>
          </Form>
        </ProCard>

        <ProCard title="按钮权限预览" size="small" variant="outlined" style={{ marginTop: 16 }}>
          <Typography.Paragraph type="secondary" style={{ marginTop: 0 }}>
            切换到「按钮权限」页签可维护完整权限码列表；此处展示当前选中菜单关联的按钮权限。
          </Typography.Paragraph>
          <Table<ButtonPermissionItem>
            rowKey="id"
            size="small"
            columns={buttonColumns}
            dataSource={relatedButtons}
            pagination={false}
          />
        </ProCard>
      </Col>
    </Row>
  );

  const buttonTab = (
    <ProCard variant="outlined">
      <Space vertical size={16} style={{ width: '100%' }}>
        <Space style={{ width: '100%', justifyContent: 'space-between' }}>
          <Typography.Text type="secondary">维护按钮级权限码，供前端 Access 与角色授权使用。</Typography.Text>
          <Button type="primary" icon={<PlusOutlined />} onClick={openCreateButton}>
            新增按钮权限
          </Button>
        </Space>
        <Table<ButtonPermissionItem>
          rowKey="id"
          columns={buttonColumns}
          dataSource={buttons}
          pagination={{ pageSize: 10, showSizeChanger: true, showTotal: total => `共 ${total} 条` }}
        />
      </Space>
    </ProCard>
  );

  return (
    <>
      <ProCard variant="outlined">
        <Typography.Title level={5} style={{ marginTop: 0 }}>
          权限配置
        </Typography.Title>
        <Typography.Paragraph type="secondary">
          维护菜单树与按钮权限码，支撑 RBAC 角色授权与前端按钮级控制。
        </Typography.Paragraph>
        <Tabs
          activeKey={activeTab}
          onChange={setActiveTab}
          items={[
            { key: 'menu', label: '菜单权限', children: menuTab },
            { key: 'button', label: '按钮权限', children: buttonTab },
          ]}
        />
      </ProCard>

      <Modal
        open={buttonOpen}
        title={editingButton ? '编辑按钮权限' : '新增按钮权限'}
        okText="保存"
        cancelText="取消"
        onOk={saveButton}
        onCancel={() => {
          setButtonOpen(false);
          buttonForm.resetFields();
        }}
      >
        <Form form={buttonForm} layout="vertical" requiredMark="optional">
          <Form.Item label="权限名称" name="name" rules={[{ required: true, message: '请输入权限名称' }]}>
            <Input placeholder="例如 新增" />
          </Form.Item>
          <Form.Item label="权限码" name="code" rules={[{ required: true, message: '请输入权限码' }]}>
            <Input placeholder="例如 system:user:add" />
          </Form.Item>
          <Form.Item label="所属菜单" name="menuKey" rules={[{ required: true, message: '请选择所属菜单' }]}>
            <Select options={menuOptions.map(item => ({ label: item.label, value: item.key }))} />
          </Form.Item>
        </Form>
      </Modal>
    </>
  );
}
