import React, { useEffect, useState, useMemo, useCallback } from 'react';
import {
  Card,
  Form,
  Input,
  Button,
  Space,
  Spin,
  Alert,
  Descriptions,
  Tag,
  Divider,
  Drawer,
  Tree,
  Select,
  TreeSelect,
  Modal,
  DatePicker,
  Row,
  Col,
  List,
} from 'antd';
import {
  SaveOutlined,
  ApiOutlined,
  CheckCircleOutlined,
  CloseCircleOutlined,
  SyncOutlined,
  BankOutlined,
  UserOutlined,
  StopOutlined,
} from '@ant-design/icons';
import type { DataNode } from 'antd/es/tree';
import type { TreeSelectProps } from 'antd/es/tree-select';
import api from '../../api';
import { message } from '../../ui/app-message';
import { usePermission } from '../../hooks/usePermission';
import PermissionButton from '../../components/PermissionButton';
import {
  buildDingTalkConfigPayload,
  isAppSecretRequired,
  type DingTalkConfigFormValues,
} from './integration-config-form';

interface DingTalkConfig {
  agentId: string;
  corpId: string;
}

interface DingOrgTreeNodeExt {
  id: number;
  name: string;
  parentId: number;
  children: DingOrgTreeNodeExt[];
  users: Array<{ userid: string; name: string; mobile: string; deptIds: number[] }>;
}

interface OrgTreeNodeRaw {
  id: number;
  name: string;
  children?: OrgTreeNodeRaw[];
}

interface OrgTreeResponse {
  success: boolean;
  data: OrgTreeNodeRaw[];
}

interface OrgTreeWithUsersResponse {
  success: boolean;
  data: DingOrgTreeNodeExt[];
}

type DeptPickerTreeNode = NonNullable<TreeSelectProps<number>['treeData']>[number];

interface ClassItem {
  id: number;
  name: string;
  code: string;
  classType?: string;
  startDate?: string;
  endDate?: string;
  notes?: string;
}

interface ImportResult {
  imported: number;
  skipped: number;
  conflicts: number;
}

interface DingTalkAttendanceGroup {
  group_id: number;
  group_name: string;
  type: string;
  member_count: number;
}

interface AttendanceGroupResponse {
  success: boolean;
  data: DingTalkAttendanceGroup[];
}

interface DeleteAttendanceGroupsResponse {
  success: boolean;
  data: {
    total: number;
    deleted: Array<{ groupId: number; groupName: string }>;
    failed: Array<{ groupId: number; groupName: string; error: string }>;
  };
}

const IntegrationConfigPage: React.FC = () => {
  const { hasAllPermissions } = usePermission();
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);
  const [testing, setTesting] = useState(false);
  const [config, setConfig] = useState<DingTalkConfig | null>(null);
  const [verified, setVerified] = useState<boolean | null>(null);
  const [form] = Form.useForm<DingTalkConfigFormValues>();

  // ── Manual organization sync ──
  const [syncRootDeptId, setSyncRootDeptId] = useState<number | undefined>(undefined);
  const [orgTree, setOrgTree] = useState<DingOrgTreeNodeExt[]>([]);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [fetchingTree, setFetchingTree] = useState(false);
  const [importing, setImporting] = useState(false);
  const [deptPickerTree, setDeptPickerTree] = useState<DeptPickerTreeNode[]>([]);
  const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
  const [selectedClassId, setSelectedClassId] = useState<number | null>(null);
  const [classes, setClasses] = useState<ClassItem[]>([]);
  const [classForm] = Form.useForm();
  const [classModalOpen, setClassModalOpen] = useState(false);
  const [attendanceGroups, setAttendanceGroups] = useState<DingTalkAttendanceGroup[]>([]);
  const [deleteGroupsOpen, setDeleteGroupsOpen] = useState(false);
  const [loadingGroups, setLoadingGroups] = useState(false);
  const [deletingGroups, setDeletingGroups] = useState(false);

  const fetchConfig = async () => {
    setLoading(true);
    try {
      const res = await api.get<{
        success: boolean;
        data: Array<{ type: string; verify: boolean; config: DingTalkConfig }>;
      }>('/integration/config');
      const dt = res.data?.find((c) => c.type === 'DINGTALK');
      if (dt) {
        setConfig(dt.config);
        setVerified(dt.verify);
        form.setFieldsValue(dt.config);
      }
    } catch {
      // not configured
    } finally {
      setLoading(false);
    }
  };

  useEffect(() => {
    void fetchConfig();
  }, []);

  const handleSave = async () => {
    const values = await form.validateFields();
    const payload = buildDingTalkConfigPayload(values);
    setSaving(true);
    try {
      await api.post('/integration/config', { type: 'DINGTALK', config: payload });
      message.success('配置已保存');
      await fetchConfig();
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '保存失败');
    } finally {
      setSaving(false);
    }
  };

  const handleTest = async () => {
    const values = await form.validateFields();
    const payload = buildDingTalkConfigPayload(values);
    setTesting(true);
    try {
      const res = await api.post<{ success: boolean; message: string }>(
        '/integration/config/test',
        {
          type: 'DINGTALK',
          config: payload,
        },
      );
      setVerified(res.success);
      message.success(res.message);
    } catch (e: unknown) {
      const err = e as { message?: string };
      setVerified(false);
      message.error(err?.message || '连接失败');
    } finally {
      setTesting(false);
    }
  };

  const loadDeptTree = async () => {
    try {
      const res = await api.get<OrgTreeResponse>('/sync/dingtalk/org-tree');
      if (res.success && res.data) {
        const toTreeNode = (nodes: OrgTreeNodeRaw[]): DeptPickerTreeNode[] =>
          nodes.map((n) => ({
            title: n.name,
            value: n.id,
            children: n.children ? toTreeNode(n.children) : undefined,
          }));
        setDeptPickerTree(toTreeNode(res.data));
      }
    } catch {
      message.error('获取部门架构失败');
    }
  };

  const fetchClasses = async () => {
    try {
      const res = await api.get<ClassItem[] | { data: ClassItem[] }>('/classes');
      if (Array.isArray(res)) {
        setClasses(res);
      } else {
        setClasses(res.data ?? []);
      }
    } catch {
      /* ignore */
    }
  };

  const handleFetchOrgTree = async () => {
    setFetchingTree(true);
    try {
      const params: Record<string, string> = {};
      if (syncRootDeptId) params.rootDeptId = String(syncRootDeptId);
      const res = await api.get<OrgTreeWithUsersResponse>('/sync/dingtalk/org-tree-with-users', {
        params,
      });
      if (res.success && res.data) {
        setOrgTree(res.data);
        setCheckedKeys([]);
        setSelectedClassId(null);
        setDrawerOpen(true);
        fetchClasses();
      } else {
        message.error('获取组织架构失败');
      }
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '获取组织架构失败');
    } finally {
      setFetchingTree(false);
    }
  };

  const buildTreeData = useCallback((nodes: DingOrgTreeNodeExt[]): DataNode[] => {
    return nodes.map((node) => {
      const users = node.users ?? [];
      const children: DataNode[] = [
        ...buildTreeData(node.children ?? []),
        ...users.map((u) => ({
          title: (
            <Space>
              <UserOutlined />
              <span>{u.name}</span>
              {u.mobile ? <Tag>{u.mobile}</Tag> : null}
            </Space>
          ),
          key: `user-${u.userid}`,
          isLeaf: true,
        })),
      ];
      return {
        title: (
          <Space size="small">
            <BankOutlined />
            <span>{node.name}</span>
            <Tag>{users.length}人</Tag>
          </Space>
        ),
        key: `dept-${node.id}`,
        // Only attach children when there are any, so empty/leaf departments
        // don't render a phantom expand arrow that opens to nothing.
        ...(children.length > 0 ? { children } : {}),
      };
    });
  }, []);

  const treeData = useMemo(() => buildTreeData(orgTree), [orgTree, buildTreeData]);

  const extractCheckedUsers = useCallback((): Array<{
    dingUserId: string;
    name: string;
    mobile?: string;
  }> => {
    const result: Array<{ dingUserId: string; name: string; mobile?: string }> = [];
    const walk = (nodes: DingOrgTreeNodeExt[]) => {
      for (const node of nodes) {
        for (const u of node.users ?? []) {
          if (checkedKeys.includes(`user-${u.userid}`)) {
            result.push({ dingUserId: u.userid, name: u.name, mobile: u.mobile || undefined });
          }
        }
        walk(node.children ?? []);
      }
    };
    walk(orgTree);
    return result;
  }, [checkedKeys, orgTree]);

  const handleJoinClass = async () => {
    if (selectedClassId === null) return message.warning('请先选择一个班级');
    const users = extractCheckedUsers();
    if (users.length === 0) return message.warning('请勾选要导入的用户');

    setImporting(true);
    try {
      const res = await api.post<ImportResult>(`/classes/${selectedClassId}/students/import`, {
        users,
      });
      if (res.conflicts > 0) {
        message.warning(
          `导入 ${res.imported} 人，跳过 ${res.skipped} 人，${res.conflicts} 人需人工绑定`,
        );
      } else {
        message.success(`导入 ${res.imported} 人，跳过 ${res.skipped} 人`);
      }
      setCheckedKeys([]);
      setSelectedClassId(null);
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '导入失败');
    } finally {
      setImporting(false);
    }
  };

  const handleCreateClass = async () => {
    try {
      const values = await classForm.validateFields();
      const users = extractCheckedUsers();
      await api.post('/classes', { ...values, users });
      message.success('班级创建成功');
      setClassModalOpen(false);
      classForm.resetFields();
      setCheckedKeys([]);
      fetchClasses();
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '创建失败');
    } finally {
      setImporting(false);
    }
  };

  const openDeleteAllGroups = async () => {
    setLoadingGroups(true);
    try {
      const response = await api.get<AttendanceGroupResponse>('/sync/dingtalk/attendance-groups');
      setAttendanceGroups(response.data);
      setDeleteGroupsOpen(true);
    } catch (error: unknown) {
      message.error(error instanceof Error ? error.message : '获取钉钉考勤组失败');
    } finally {
      setLoadingGroups(false);
    }
  };

  const deleteAllGroups = async () => {
    setDeletingGroups(true);
    try {
      const response = await api.post<DeleteAttendanceGroupsResponse>(
        '/sync/dingtalk/attendance-groups/delete-all',
      );
      setDeleteGroupsOpen(false);
      setAttendanceGroups([]);
      if (response.data.failed.length > 0) {
        message.warning(
          `已清空 ${response.data.deleted.length} 个，失败 ${response.data.failed.length} 个`,
        );
      } else {
        message.success(`已清空钉钉全部 ${response.data.deleted.length} 个考勤组`);
      }
    } catch (error: unknown) {
      message.error(error instanceof Error ? error.message : '清空钉钉考勤组失败');
    } finally {
      setDeletingGroups(false);
    }
  };

  const syncPanel =
    config && hasAllPermissions('sync:read', 'class:view', 'class:edit') ? (
      <div>
        <Alert
          type="info"
          message="从钉钉获取组织架构，勾选用户后批量导入到班级。"
          style={{ marginBottom: 16 }}
          showIcon
        />
        <Space>
          <TreeSelect
            treeData={deptPickerTree}
            value={syncRootDeptId}
            onChange={(v) => setSyncRootDeptId(v)}
            placeholder="选择起始部门（不选=全部）"
            allowClear
            treeDefaultExpandAll
            style={{ minWidth: 240 }}
            onDropdownVisibleChange={(open) => {
              if (open) loadDeptTree();
            }}
          />
          <Button
            type="primary"
            icon={<SyncOutlined />}
            loading={fetchingTree}
            onClick={handleFetchOrgTree}
          >
            获取组织架构
          </Button>
          <PermissionButton
            permission="sync:trigger"
            danger
            icon={<StopOutlined />}
            loading={loadingGroups}
            onClick={openDeleteAllGroups}
          >
            清空钉钉全部考勤组
          </PermissionButton>
        </Space>

        {drawerOpen && (
          <Drawer
            title="钉钉组织架构 — 批量导入"
            open={drawerOpen}
            onClose={() => {
              setDrawerOpen(false);
            }}
            width="min(900px, 100vw)"
            footer={
              <Space>
                <Button
                  onClick={() => {
                    setDrawerOpen(false);
                  }}
                >
                  取消
                </Button>
                <Button
                  type="primary"
                  loading={importing}
                  disabled={
                    checkedKeys.filter((k) => String(k).startsWith('user-')).length === 0 ||
                    selectedClassId === null
                  }
                  onClick={handleJoinClass}
                >
                  加入选中的班级
                </Button>
                <Button
                  disabled={checkedKeys.filter((k) => String(k).startsWith('user-')).length === 0}
                  onClick={() => setClassModalOpen(true)}
                >
                  创建班级
                </Button>
              </Space>
            }
          >
            <Row gutter={[16, 16]}>
              <Col xs={24} md={14}>
                <div style={{ maxHeight: '60vh', overflow: 'auto' }}>
                  <Tree
                    checkable
                    treeData={treeData}
                    defaultExpandAll
                    showLine={{ showLeafIcon: false }}
                    checkedKeys={checkedKeys}
                    onCheck={(checked) => setCheckedKeys(checked as React.Key[])}
                  />
                </div>
              </Col>
              <Col xs={24} md={10}>
                <Card
                  title="班级列表"
                  size="small"
                  extra={
                    <Button size="small" onClick={() => setClassModalOpen(true)}>
                      + 创建班级
                    </Button>
                  }
                >
                  <List
                    dataSource={classes}
                    renderItem={(cls: ClassItem) => (
                      <List.Item
                        onClick={() => setSelectedClassId(cls.id)}
                        style={{
                          cursor: 'pointer',
                          background: selectedClassId === cls.id ? '#e6f4ff' : undefined,
                          borderRadius: 4,
                          padding: '8px 12px',
                        }}
                      >
                        <List.Item.Meta
                          title={cls.name}
                          description={`${cls.code}  ${cls.classType || ''}`}
                        />
                      </List.Item>
                    )}
                  />
                </Card>
              </Col>
            </Row>

            {/* Create class Modal */}
            <Modal
              title="创建班级"
              open={classModalOpen}
              onOk={handleCreateClass}
              onCancel={() => {
                setClassModalOpen(false);
                classForm.resetFields();
              }}
              confirmLoading={importing}
              destroyOnClose
            >
              <Form form={classForm} layout="vertical">
                <Form.Item name="name" label="班级名称" rules={[{ required: true }]}>
                  <Input />
                </Form.Item>
                <Form.Item name="code" label="班级编码" rules={[{ required: true }]}>
                  <Input placeholder="如 CS2024-01" />
                </Form.Item>
                <Form.Item name="classType" label="班型" rules={[{ required: true }]}>
                  <Select
                    options={[
                      { value: 'culture', label: '文化课' },
                      { value: 'professional', label: '专业课' },
                      { value: 'bootcamp', label: '集训营' },
                      { value: 'sprint', label: '冲刺班' },
                    ]}
                  />
                </Form.Item>
                <Form.Item name="startDate" label="开班日期">
                  <DatePicker style={{ width: '100%' }} />
                </Form.Item>
                <Form.Item name="endDate" label="结束日期">
                  <DatePicker style={{ width: '100%' }} />
                </Form.Item>
                <Form.Item name="notes" label="备注">
                  <Input.TextArea rows={2} />
                </Form.Item>
              </Form>
            </Modal>
          </Drawer>
        )}
        <Modal
          title="确认清空钉钉全部考勤组"
          open={deleteGroupsOpen}
          okText="确认全部清空"
          okButtonProps={{ danger: true, disabled: attendanceGroups.length === 0 }}
          cancelText="取消"
          confirmLoading={deletingGroups}
          onOk={deleteAllGroups}
          onCancel={() => setDeleteGroupsOpen(false)}
        >
          <Alert
            type="error"
            showIcon
            message={`将永久清空钉钉上的 ${attendanceGroups.length} 个考勤组`}
            description="本地班级和排课不会清空。清空后需在排课管理中重新同步，才能重建考勤组。"
            style={{ marginBottom: 12 }}
          />
          <List
            size="small"
            bordered
            dataSource={attendanceGroups}
            style={{ maxHeight: 280, overflow: 'auto' }}
            renderItem={(group) => (
              <List.Item>
                <List.Item.Meta
                  title={group.group_name}
                  description={`ID ${group.group_id} · ${group.member_count} 人`}
                />
              </List.Item>
            )}
          />
        </Modal>
      </div>
    ) : null;

  return (
    <Card
      title="钉钉集成配置"
      extra={
        <Space>
          {verified === true && (
            <Tag icon={<CheckCircleOutlined />} color="success">
              已连接
            </Tag>
          )}
          {verified === false && (
            <Tag icon={<CloseCircleOutlined />} color="error">
              未连接
            </Tag>
          )}
        </Space>
      }
    >
      <Spin spinning={loading}>
        {config && (
          <Descriptions size="small" column={2} style={{ marginBottom: 24 }}>
            <Descriptions.Item label="CorpId">{config.corpId || '-'}</Descriptions.Item>
            <Descriptions.Item label="AppKey">{config.agentId || '-'}</Descriptions.Item>
            <Descriptions.Item label="同步方式">手动触发</Descriptions.Item>
          </Descriptions>
        )}

        <Alert
          type="info"
          message="配置钉钉应用凭证后，可在本页手动获取组织架构并导入用户。排班同步仍在排课管理中手动触发。"
          style={{ marginBottom: 24 }}
          showIcon
        />

        <Form form={form} layout="vertical" style={{ maxWidth: 520 }}>
          <Form.Item
            name="corpId"
            label="CorpId（企业ID）"
            rules={[{ required: true, message: '请输入 CorpId' }]}
          >
            <Input placeholder="dingxxxxxxxx" />
          </Form.Item>
          <Form.Item
            name="agentId"
            label="AppKey（应用凭证）"
            rules={[{ required: true, message: '请输入 AppKey' }]}
          >
            <Input placeholder="从钉钉开放平台获取" />
          </Form.Item>
          <Form.Item
            name="appSecret"
            label="AppSecret（应用密钥）"
            rules={[
              {
                required: isAppSecretRequired(!!config),
                message: '首次配置请输入 AppSecret',
              },
            ]}
            extra={
              config
                ? '已保存密钥；留空保持原值，输入新值将替换原密钥'
                : '首次配置需要填写完整 AppSecret'
            }
          >
            <Input.Password placeholder={config ? '留空保持已保存的密钥' : '从钉钉开放平台获取'} />
          </Form.Item>
          <Space>
            <PermissionButton
              permission="integration:trigger"
              type="primary"
              icon={<SaveOutlined />}
              loading={saving}
              onClick={handleSave}
            >
              保存配置
            </PermissionButton>
            <Button icon={<ApiOutlined />} loading={testing} onClick={handleTest}>
              测试连接
            </Button>
          </Space>
        </Form>

        {syncPanel && (
          <>
            <Divider titlePlacement="start">组织用户导入</Divider>
            {syncPanel}
          </>
        )}
      </Spin>
    </Card>
  );
};

export default IntegrationConfigPage;
