import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
  App,
  Form,
} from 'antd';
import api from '../../api';
import { usePermission } from '../../hooks/usePermission';
import { useUserStore } from '../../store/user/userStore';
import { selectArchiveRecords } from '../archive-view';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useApiMutation } from '../../hooks/useApiMutation';
import { validateResponse } from '../../utils/validate';
import {
  organizationOptionsSchema,
  organizationsSchema,
  studentFilterLookupsSchema,
  studentsSchema,
} from '../../api/schemas';
import { getErrorMessage } from '../../utils/error';
import { message } from '../../ui/app-message';
import { buildStudentColumns } from './StudentColumns';
import { StudentsToolbar } from './StudentsToolbar';
import {
  JinshujuModal,
  StudentDrawer,
  StudentEditModal,
  showCreateImportResult,
  showUpdateImportResult,
} from './StudentModals';
import { StudentsTable } from './StudentsTable';

interface StudentCreateImportResult {
  message?: string;
  imported?: number;
  skipped?: number;
}

interface StudentUpdateImportResult {
  message?: string;
  matched?: number;
  skipped?: number;
}

interface DingTalkSyncLog {
  status: string;
  recordsCount: number;
  errorMessage?: string | null;
}

interface DingTalkSyncResult {
  synced: number;
  logs: DingTalkSyncLog[];
}

interface StudentFilterLookups {
  classes: Array<{ id: number; name: string; code?: string }>;
  teachers: Array<{ id: number; name: string; username: string }>;
}

const StudentsPage: React.FC = () => {
  const { modal } = App.useApp();
  const { hasPermission, hasAnyPermission, hasAllPermissions } = usePermission();
  const canViewOrganizations = hasPermission('organization:view');
  const canLoadOrganizations = hasAnyPermission(
    'organization:view',
    'student:create',
    'student:edit',
  );
  const canChooseOrganization = hasAnyPermission('student:create', 'student:edit');
  const canCreateStudent = hasPermission('student:create');
  const canEditStudent = hasPermission('student:edit');
  const canDeleteStudent = hasPermission('student:delete');
  const canPurgeStudent = hasPermission('student:purge');
  const canSyncJinshuju = hasAllPermissions('sync:read', 'sync:trigger');
  const canSyncDingTalk = hasAllPermissions('sync:read', 'sync:trigger');
  const [modalOpen, setModalOpen] = useState(false);
  const [editing, setEditing] = useState<any>(null);
  const canSaveStudent = editing ? canEditStudent : canCreateStudent;
  const [searchName, setSearchName] = useState('');
  const [filterStatus, setFilterStatus] = useState<string | undefined>(undefined);
  const [filterOrganizationId, setFilterOrganizationId] = useState<number | undefined>(undefined);
  const effectiveFilterOrganizationId = canLoadOrganizations ? filterOrganizationId : undefined;
  const [filterClassId, setFilterClassId] = useState<number | undefined>(undefined);
  const [filterTeacherId, setFilterTeacherId] = useState<number | undefined>(undefined);
  const [showArchived, setShowArchived] = useState(false);
  const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
  const [batchLoading, setBatchLoading] = useState(false);
  const [dingSyncLoading, setDingSyncLoading] = useState(false);
  const [pageInfo, setPageInfo] = useState({ current: 1, pageSize: 15 });
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [drawerStudentId, setDrawerStudentId] = useState<number | undefined>(undefined);
  const [form] = Form.useForm();
  const [saving, setSaving] = useState(false);
  const [jinshujuOpen, setJinshujuOpen] = useState(false);

  const openDrawer = useCallback((studentId: number) => {
    setDrawerStudentId(studentId);
    setDrawerOpen(true);
  }, []);

  const logCreateRef = React.useRef(hasPermission('log:create'));
  const sensitiveModalRef = React.useRef<ReturnType<typeof modal.confirm> | null>(null);
  logCreateRef.current = hasPermission('log:create');
  useEffect(() => {
    if (!logCreateRef.current && sensitiveModalRef.current) {
      sensitiveModalRef.current.destroy();
      sensitiveModalRef.current = null;
    }
    return () => {
      sensitiveModalRef.current?.destroy();
      sensitiveModalRef.current = null;
    };
  }, []);

  const handleViewSensitive = useCallback(
    (studentId: number, field: string, value: string) => {
      if (!logCreateRef.current) return;
      sensitiveModalRef.current = modal.confirm({
        title: '查看敏感信息',
        content: `您即将查看 "${field}" 的完整信息。此操作将被记录。`,
        okText: '确认查看',
        cancelText: '取消',
        onOk: async () => {
          if (!logCreateRef.current) return;
          try {
            await api.post('/operation-logs/audit', {
              module: '学生管理',
              action: '查看敏感信息',
              targetId: studentId,
              targetType: 'student',
              detail: `查看${field}`,
            });
            modal.info({
              title: field,
              content: value,
              okText: '关闭',
            });
          } catch (e) {
            console.error('审计日志记录失败', e);
            message.error('审计日志记录失败，请稍后重试');
          }
        },
        afterClose: () => {
          sensitiveModalRef.current = null;
        },
      });
    },
    [modal],
  );

  const {
    data = [],
    isLoading,
    isFetching,
  } = useQuery<any[]>({
    queryKey: [
      'students',
      searchName,
      showArchived,
      filterStatus,
      effectiveFilterOrganizationId,
      filterClassId,
      filterTeacherId,
    ],
    queryFn: async () => {
      try {
        const params: Record<string, unknown> = {
          name: searchName || undefined,
          includeArchived: showArchived ? 'true' : undefined,
        };
        if (showArchived) params.status = 'archived';
        else if (filterStatus) params.status = filterStatus;
        if (effectiveFilterOrganizationId) params.organizationId = effectiveFilterOrganizationId;
        if (filterClassId) params.classId = filterClassId;
        if (filterTeacherId) params.teacherId = filterTeacherId;
        const res = (await api.get('/students', { params })) as Array<Record<string, unknown>>;
        return selectArchiveRecords(
          validateResponse<Array<Record<string, unknown>>>(studentsSchema, res),
          showArchived ? 'archived' : 'active',
        );
      } catch (e: unknown) {
        message.error(getErrorMessage(e, '加载失败，请稍后重试'));
        return [];
      }
    },
  });
  const loading = isLoading || isFetching;

  const queryClient = useQueryClient();
  const invalidateStudents: Array<readonly unknown[]> = [['students']];
  const saveMutation = useApiMutation(
    async (values: Record<string, unknown>) =>
      editing ? api.put(`/students/${editing.id}`, values) : api.post('/students', values),
    { invalidate: invalidateStudents },
  );
  const saveCellMutation = useApiMutation(
    async ({ record, field, value }: { record: any; field: string; value: unknown }) =>
      api.put(`/students/${record.id}`, { [field]: value }),
    { invalidate: invalidateStudents },
  );
  const archiveMutation = useApiMutation(
    async (id: number) => api.delete(`/students/${id}`),
    { invalidate: invalidateStudents },
  );
  const restoreMutation = useApiMutation(
    async (id: number) => api.put(`/students/${id}/restore`),
    { invalidate: invalidateStudents },
  );
  const purgeMutation = useApiMutation(
    async (id: number) => api.delete(`/students/${id}/permanent`),
    { invalidate: invalidateStudents },
  );
  const batchDeleteMutation = useApiMutation(
    async (ids: number[]) => api.post('/students/batch-delete', { ids }),
    { invalidate: invalidateStudents },
  );
  const batchRestoreMutation = useApiMutation(
    async (ids: number[]) =>
      api.put<{ message?: string; restored: number; skipped: number }>(
        '/students/batch-restore',
        { ids },
      ),
    { invalidate: invalidateStudents },
  );
  const batchPurgeMutation = useApiMutation(
    async (ids: number[]) => api.post('/students/batch-permanent-delete', { ids }),
    { invalidate: invalidateStudents },
  );
  const importMutation = useApiMutation(
    async (formData: FormData) =>
      api.post('/students/import', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      }),
    { invalidate: invalidateStudents },
  );
  const importMatchMutation = useApiMutation(
    async (formData: FormData) =>
      api.post('/students/import-match', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      }),
    { invalidate: invalidateStudents },
  );

  const { data: organizations = [] } = useQuery<
    Array<{ id: number; name: string; isHost?: boolean }>
  >({
    queryKey: ['students', 'organizations', canViewOrganizations],
    enabled: canLoadOrganizations,
    queryFn: async () => {
      try {
        if (canViewOrganizations) {
          return validateResponse<Array<{ id: number; name: string; isHost?: boolean }>>(
            organizationsSchema,
            await api.get('/organizations', {
              params: { includeArchived: 'false' },
            }),
          );
        }
        return validateResponse<Array<{ id: number; name: string; isHost?: boolean }>>(
          organizationOptionsSchema,
          await api.get('/organizations/options'),
        );
      } catch {
        return [];
      }
    },
  });
  const { data: lookups = { classes: [], teachers: [] } } = useQuery<StudentFilterLookups>({
    queryKey: ['students', 'filter-lookups'],
    enabled: canLoadOrganizations,
    queryFn: async () => {
      try {
        return validateResponse<StudentFilterLookups>(
          studentFilterLookupsSchema,
          await api.get<StudentFilterLookups>('/students/filter-lookups'),
        );
      } catch {
        return { classes: [], teachers: [] };
      }
    },
  });
  const classOptions = lookups.classes || [];
  const teacherOptions = lookups.teachers || [];

  const handleSave = async () => {
    const values = await form.validateFields();
    setSaving(true);
    try {
      await saveMutation.mutateAsync(values);
      message.success(editing ? '更新成功' : '创建成功');
      setModalOpen(false);
      form.resetFields();
      setEditing(null);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSaving(false);
    }
  };

  const saveCell = useCallback(
    async (record: any, field: string, value: unknown) => {
      try {
        await saveCellMutation.mutateAsync({ record, field, value });
        message.success('已保存');
      } catch {
        // 错误提示由 useApiMutation 统一处理
      }
    },
    [saveCellMutation],
  );

  const downloadApiFile = async (path: string, filename: string, errorMessage = '下载失败') => {
    const baseURL = import.meta.env.PROD
      ? '/api'
      : `http://localhost:${import.meta.env.VITE_API_PORT || 3002}/api`;
    const token = useUserStore.getState().token;
    try {
      const res = await fetch(`${baseURL}${path}`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      const blob = await res.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      a.click();
      URL.revokeObjectURL(url);
    } catch (error: unknown) {
      console.error(errorMessage, error);
      message.error(errorMessage);
    }
  };

  const handleArchive = useCallback(
    async (id: number) => {
      try {
        await archiveMutation.mutateAsync(id);
        message.success('已归档');
      } catch {
        // 错误提示由 useApiMutation 统一处理
      }
    },
    [archiveMutation],
  );

  const handleRestore = useCallback(
    async (id: number) => {
      try {
        await restoreMutation.mutateAsync(id);
        message.success('已恢复');
      } catch {
        // 错误提示由 useApiMutation 统一处理
      }
    },
    [restoreMutation],
  );

  const handlePurge = useCallback(
    (id: number, name: string) => {
      modal.confirm({
        title: `永久删除学生「${name}」？`,
        content: '删除后不可恢复，该学生及其关联数据将无法找回。确定继续？',
        okText: '永久删除',
        okButtonProps: { danger: true },
        cancelText: '取消',
        onOk: async () => {
          try {
            await purgeMutation.mutateAsync(id);
            message.success('已永久删除（不可恢复）');
          } catch {
            // 错误提示由 useApiMutation 统一处理
          }
        },
      });
    },
    [modal, purgeMutation],
  );

  const handleBatchDelete = async () => {
    if (batchLoading) return;
    setBatchLoading(true);
    try {
      const res: any = await batchDeleteMutation.mutateAsync(selectedRowKeys);
      message.success(res?.message || `已批量归档 ${selectedRowKeys.length} 人`);
      setSelectedRowKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchRestore = async () => {
    if (batchLoading) return;
    setBatchLoading(true);
    try {
      const res = await batchRestoreMutation.mutateAsync(selectedRowKeys);
      message.success(
        `已批量恢复 ${res.restored} 人${res.skipped ? `，跳过 ${res.skipped} 人` : ''}`,
      );
      setSelectedRowKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchPurge = async () => {
    if (batchLoading) return;
    setBatchLoading(true);
    try {
      const res: any = await batchPurgeMutation.mutateAsync(selectedRowKeys);
      message.success(res?.message || `已永久删除 ${selectedRowKeys.length} 人`);
      setSelectedRowKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleDownloadTemplate = () => {
    void downloadApiFile('/students/template', '学生导入模板.xlsx');
  };

  const handleCreateStudentsImport = async ({ file, onSuccess, onError }: any) => {
    const formData = new FormData();
    formData.append('file', file as File);
    try {
      const res = (await importMutation.mutateAsync(formData)) as StudentCreateImportResult;
      showCreateImportResult(modal, res);
      onSuccess?.(res);
    } catch (e) {
      onError?.(e instanceof Error ? e : new Error(getErrorMessage(e, '导入失败')));
    }
  };

  const handleUpdateExistingStudentsImport = async ({ file, onSuccess, onError }: any) => {
    const formData = new FormData();
    formData.append('file', file as File);
    try {
      const res = (await importMatchMutation.mutateAsync(formData)) as StudentUpdateImportResult;
      showUpdateImportResult(modal, res);
      onSuccess?.(res);
    } catch (e) {
      onError?.(
        e instanceof Error ? e : new Error(getErrorMessage(e, '更新已有学生资料失败')),
      );
    }
  };

  const handleDingTalkSync = async () => {
    setDingSyncLoading(true);
    try {
      const res = await api.post<DingTalkSyncResult>('/sync/trigger', null, {
        params: { platform: 'dingtalk_students', createMissing: false, updateProfile: false },
        timeout: 120000,
      });
      const log = res.logs?.[0];
      if (log?.status === 'partial') {
        message.warning(log.errorMessage || '钉钉同步完成，但有数据需要人工处理');
      } else {
        message.success(
          log?.errorMessage || `钉钉同步完成，共处理 ${log?.recordsCount ?? res.synced} 条`,
        );
      }
      void queryClient.invalidateQueries({ queryKey: ['students'] });
    } catch (e: unknown) {
      message.error(getErrorMessage(e, '钉钉同步失败'));
    } finally {
      setDingSyncLoading(false);
    }
  };

  const handleExport = () => {
    const params = new URLSearchParams();
    if (searchName) params.set('name', searchName);
    if (filterStatus) params.set('status', filterStatus);
    if (effectiveFilterOrganizationId)
      params.set('organizationId', String(effectiveFilterOrganizationId));
    if (showArchived) params.set('includeArchived', 'true');
    if (filterClassId) params.set('classId', String(filterClassId));
    if (filterTeacherId) params.set('teacherId', String(filterTeacherId));
    const query = params.toString() ? `?${params.toString()}` : '';
    void downloadApiFile(`/students/export${query}`, '学生名单.xlsx', '导出失败');
  };

  const columns = useMemo(
    () =>
      buildStudentColumns({
        pageInfo,
        organizations,
        canChooseOrganization,
        canEditStudent,
        canDeleteStudent,
        canPurgeStudent,
        canViewSensitive: hasPermission('log:create'),
        onSaveCell: saveCell,
        onViewSensitive: handleViewSensitive,
        onOpenDrawer: openDrawer,
        onEdit: (record) => {
          setEditing(record);
          form.setFieldsValue(record);
          setModalOpen(true);
        },
        onRestore: handleRestore,
        onPurge: handlePurge,
        onArchive: handleArchive,
      }),
    [
      pageInfo,
      organizations,
      canChooseOrganization,
      canEditStudent,
      canDeleteStudent,
      canPurgeStudent,
      hasPermission,
      saveCell,
      handleViewSensitive,
      form,
      openDrawer,
      handleArchive,
      handleRestore,
      handlePurge,
    ],
  );

  return (
    <div>
      <StudentsToolbar
        onSearchName={setSearchName}
        filterStatus={filterStatus}
        onFilterStatus={setFilterStatus}
        effectiveFilterOrganizationId={effectiveFilterOrganizationId}
        onFilterOrganization={setFilterOrganizationId}
        canViewOrganizations={canViewOrganizations}
        organizations={organizations}
        filterClassId={filterClassId}
        onFilterClass={setFilterClassId}
        classOptions={classOptions}
        filterTeacherId={filterTeacherId}
        onFilterTeacher={setFilterTeacherId}
        teacherOptions={teacherOptions}
        showArchived={showArchived}
        onToggleArchived={() => {
          setShowArchived(!showArchived);
          setFilterStatus(undefined);
          setSelectedRowKeys([]);
        }}
        selectedRowKeys={selectedRowKeys}
        batchLoading={batchLoading}
        canEditStudent={canEditStudent}
        canPurgeStudent={canPurgeStudent}
        canDeleteStudent={canDeleteStudent}
        canSyncJinshuju={canSyncJinshuju}
        canSyncDingTalk={canSyncDingTalk}
        dingSyncLoading={dingSyncLoading}
        onBatchRestore={handleBatchRestore}
        onBatchPurge={handleBatchPurge}
        onBatchDelete={handleBatchDelete}
        onAddStudent={() => {
          setEditing(null);
          form.resetFields();
          const host = organizations.find((organization) => organization.isHost);
          if (host) form.setFieldValue('organizationId', host.id);
          setModalOpen(true);
        }}
        onOpenJinshuju={() => setJinshujuOpen(true)}
        onDingTalkSync={handleDingTalkSync}
        onCreateImport={handleCreateStudentsImport}
        onUpdateImport={handleUpdateExistingStudentsImport}
        onDownloadTemplate={handleDownloadTemplate}
        onExport={handleExport}
      />
      <StudentsTable
        columns={columns}
        data={data}
        loading={loading}
        pageInfo={pageInfo}
        onPageChange={(current, pageSize) => setPageInfo({ current, pageSize })}
        selectedRowKeys={selectedRowKeys}
        onSelect={setSelectedRowKeys}
        onClearSelection={() => setSelectedRowKeys([])}
      />
      <StudentEditModal
        open={modalOpen && canSaveStudent}
        editing={!!editing}
        saving={saving}
        form={form}
        canChooseOrganization={canChooseOrganization}
        organizations={organizations}
        onOk={canSaveStudent ? handleSave : undefined}
        onCancel={() => {
          setModalOpen(false);
          setEditing(null);
        }}
      />
      {canSyncJinshuju ? (
        <JinshujuModal
          open={jinshujuOpen && canSyncJinshuju}
          onClose={() => setJinshujuOpen(false)}
          onApplied={() => {
            setJinshujuOpen(false);
            void queryClient.invalidateQueries({ queryKey: ['students'] });
          }}
        />
      ) : null}
      <StudentDrawer open={drawerOpen} studentId={drawerStudentId ?? null} onClose={() => setDrawerOpen(false)} />
    </div>
  );
};

export default StudentsPage;
