// aislop-ignore-file: duplicate-block -- 表格/表单声明结构相似且参数不同，渲染逻辑已共享组件化
import React, { useCallback, useMemo, useState } from 'react';
import {
  Form,
  Input,
  Select,
  Space,
} from 'antd';
import { PlusOutlined, TeamOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import api from '../../api';
import PermissionButton from '../../components/PermissionButton';
import { message } from '../../ui/app-message';
import { buildDepositStudentOptions, type DepositStudentLookup } from './deposit-student-option';
import { usePermission } from '../../hooks/usePermission';
import { useQuery, useQueryClient, type QueryKey } from '@tanstack/react-query';
import { useApiMutation } from '../../hooks/useApiMutation';
import { validateResponse } from '../../utils/validate';
import {
  depositStudentLookupsSchema,
  depositsSchema,
  eligibleStudentsSchema,
} from '../../api/schemas';
import {
  DepositModals,
  roomTypeOptions,
  suggestedDepositByRoomType,
} from './DepositModals';
import type { DepositRecord, EligibleStudent } from './DepositModals';
import { DepositTable } from './DepositTable';
import { QueryErrorState } from '../../components/QueryState';
import { useVisibleRefetch } from '../../hooks/usePageVisible';

const DepositsPage: React.FC = () => {
  const { hasPermission } = usePermission();
  const canPurgeDeposit = hasPermission('deposit:purge');
  const [selectedEligibleStudentIds, setSelectedEligibleStudentIds] = useState<number[]>([]);
  const [selectionTouched, setSelectionTouched] = useState(false);
  const [eligibleRoomType, setEligibleRoomType] = useState<string | undefined>(undefined);
  const queryClient = useQueryClient();
  const [createModal, setCreateModal] = useState(false);
  const [batchModal, setBatchModal] = useState(false);
  const [refundModal, setRefundModal] = useState<DepositRecord | null>(null);
  const [detailModal, setDetailModal] = useState<DepositRecord | null>(null);
  const [installmentModal, setInstallmentModal] = useState<number | null>(null);
  const [createForm] = Form.useForm();
  const [batchForm] = Form.useForm();
  const [refundForm] = Form.useForm();
  const [installmentForm] = Form.useForm();
  const [searchText, setSearchText] = useState('');
  const [filterStatus, setFilterStatus] = useState<string | undefined>(undefined);
  const [filterRoomType, setFilterRoomType] = useState<string | undefined>(undefined);
  const [batchRoomType, setBatchRoomType] = useState<string>('四人间');
  const [saving, setSaving] = useState(false);

  const {
    data: fetchResult = { data: [], students: [] },
    isLoading,
    isFetching,
    isError,
    refetch,
  } = useQuery<{ data: DepositRecord[]; students: DepositStudentLookup[] }>({
    queryKey: ['deposits'],
    queryFn: async () => {
      const [d, s] = await Promise.all([
        api.get<DepositRecord[]>('/deposits'),
        api.get<DepositStudentLookup[]>('/deposits/student-lookups'),
      ]);
      return {
        data: validateResponse<DepositRecord[]>(depositsSchema, d),
        students: validateResponse<DepositStudentLookup[]>(depositStudentLookupsSchema, s),
      };
    },
  });
  const data = fetchResult.data;
  const students = fetchResult.students;
  const loading = isLoading || isFetching;
  // RouteKeeper 保活页面切回时刷新押金列表
  useVisibleRefetch(['deposits']);

  const invalidateDeposits: QueryKey[] = [['deposits'], ['deposits', 'eligible']];
  const createMutation = useApiMutation(
    async (payload: Record<string, unknown>) => api.post('/deposits', payload),
    { invalidate: invalidateDeposits },
  );
  const batchCreateMutation = useApiMutation(
    async (payload: Record<string, unknown>) => api.post('/deposits/batch', payload),
    { invalidate: invalidateDeposits },
  );
  const refundMutation = useApiMutation(
    async ({ id, payload }: { id: number; payload: Record<string, unknown> }) =>
      api.put(`/deposits/${id}/refund`, payload),
    { invalidate: invalidateDeposits },
  );
  const addInstallmentMutation = useApiMutation(
    async ({ id, payload }: { id: number; payload: Record<string, unknown> }) =>
      api.post(`/deposits/${id}/installments`, payload),
    { invalidate: [['deposits']] },
  );
  const payInstallmentMutation = useApiMutation(
    async (installmentId: number) =>
      api.put(`/deposits/installments/${installmentId}`, {
        status: 'paid',
        paidDate: dayjs().format('YYYY-MM-DD'),
      }),
    { invalidate: [['deposits']] },
  );
  const saveInstallmentCellMutation = useApiMutation(
    async ({
      installmentId,
      field,
      value,
    }: {
      installmentId: number;
      field: 'status' | 'paidDate';
      value: unknown;
    }) => api.put(`/deposits/installments/${installmentId}`, { [field]: value }),
    { invalidate: [['deposits']] },
  );
  const deleteInstallmentMutation = useApiMutation(
    async (installmentId: number) => api.delete(`/deposits/installments/${installmentId}`),
    { invalidate: [['deposits']] },
  );
  const archiveMutation = useApiMutation(
    async (id: number) => api.delete(`/deposits/${id}`),
    { invalidate: invalidateDeposits },
  );
  const purgeMutation = useApiMutation(
    async (id: number) => api.delete(`/deposits/${id}/permanent`),
    { invalidate: invalidateDeposits },
  );

  const {
    data: eligibleStudents = [],
    isFetching: eligibleFetching,
    isError: eligibleError,
    refetch: refetchEligible,
  } = useQuery<EligibleStudent[]>({
    queryKey: ['deposits', 'eligible', eligibleRoomType],
    queryFn: async () => {
      const params: Record<string, string> = {};
      if (eligibleRoomType) params.roomType = eligibleRoomType;
      return validateResponse<EligibleStudent[]>(
        eligibleStudentsSchema,
        await api.get('/deposits/eligible-students', { params }),
      );
    },
  });
  const eligibleLoading = eligibleFetching;
  const effectiveSelectedEligibleIds = selectionTouched
    ? selectedEligibleStudentIds
    : eligibleStudents.map((item) => item.studentId);
  const fetchEligibleStudents = useCallback(
    (roomType?: string) => {
      setEligibleRoomType(roomType);
      queryClient.invalidateQueries({ queryKey: ['deposits', 'eligible'] });
    },
    [queryClient],
  );

  const changeFilterRoomType = (value: string | undefined) => {
    setFilterRoomType(value);
    setSelectionTouched(false);
    fetchEligibleStudents(value);
  };

  const depositByStudentId = useMemo(() => {
    const map = new Map<number, DepositRecord>();
    for (const item of data) map.set(item.studentId, item);
    return map;
  }, [data]);

  const filteredData = useMemo(() => {
    if (filterRoomType) {
      const s = searchText.trim().toLowerCase();
      return eligibleStudents
        .filter(
          (item) =>
            !s ||
            item.studentName.toLowerCase().includes(s) ||
            item.studentNo?.toLowerCase().includes(s),
        )
        .map((item) => {
          const deposit = depositByStudentId.get(item.studentId);
          return {
            id: deposit?.id ?? `eligible-${item.studentId}`,
            studentId: item.studentId,
            amount: deposit?.amount ?? item.depositAmount ?? 0,
            status: deposit?.status ?? 'unpaid',
            paidDate: deposit?.paidDate ?? '',
            refundDate: deposit?.refundDate,
            notes: deposit?.notes,
            installments: deposit?.installments ?? [],
            student: {
              id: item.studentId,
              name: item.studentName,
              studentNo: item.studentNo,
              roomType: item.roomType,
            },
            roomNumber: item.roomNumber,
            building: item.building,
            roomType: item.roomType,
          };
        });
    }
    return data.filter((d) => {
      if (searchText) {
        const s = searchText.toLowerCase();
        if (!d.student?.name?.toLowerCase().includes(s)) return false;
      }
      if (filterStatus && d.status !== filterStatus) return false;
      return true;
    });
  }, [data, depositByStudentId, eligibleStudents, filterRoomType, filterStatus, searchText]);

  const studentOptions = useMemo(() => buildDepositStudentOptions(students), [students]);

  const openBatchModal = (roomType = filterRoomType || '四人间') => {
    const amount = suggestedDepositByRoomType[roomType] ?? 100;
    setBatchRoomType(roomType);
    setSelectionTouched(false);
    fetchEligibleStudents(roomType);
    batchForm.resetFields();
    batchForm.setFieldsValue({ roomType, amount, paidDate: dayjs() });
    setBatchModal(true);
  };

  const openCreateDeposit = () => {
    createForm.resetFields();
    createForm.setFieldsValue({ amount: 500, paidDate: dayjs() });
    setCreateModal(true);
  };

  const handleBatchRoomTypeChange = (roomType: string) => {
    setBatchRoomType(roomType);
    // 切换房型后候选学生列表会变化，重置勾选状态，避免把上一房型的选择提交到新房型
    setSelectionTouched(false);
    setSelectedEligibleStudentIds([]);
    batchForm.setFieldsValue({
      amount: suggestedDepositByRoomType[roomType] ?? batchForm.getFieldValue('amount') ?? 100,
    });
    fetchEligibleStudents(roomType);
  };

  const handleCreate = async () => {
    setSaving(true);
    try {
      const values = await createForm.validateFields();
      await createMutation.mutateAsync({
        studentId: values.studentId,
        amount: values.amount,
        paidDate: values.paidDate.format('YYYY-MM-DD'),
        notes: values.notes,
      });
      message.success('押金收取成功');
      setCreateModal(false);
      createForm.resetFields();
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSaving(false);
    }
  };

  const handleBatchCreate = async () => {
    setSaving(true);
    try {
      const values = await batchForm.validateFields();
      await batchCreateMutation.mutateAsync({
        studentIds: effectiveSelectedEligibleIds,
        amount: values.amount,
        paidDate: values.paidDate.format('YYYY-MM-DD'),
        notes: values.notes,
        roomType: values.roomType,
      });
      message.success('批量收取成功');
      setBatchModal(false);
      batchForm.resetFields();
      setSelectionTouched(false);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSaving(false);
    }
  };

  const handleRefund = async () => {
    if (!refundModal) return;
    setSaving(true);
    try {
      const values = await refundForm.validateFields();
      await refundMutation.mutateAsync({
        id: refundModal.id,
        payload: {
          refundDate: values.refundDate.format('YYYY-MM-DD'),
          notes: values.notes,
        },
      });
      message.success('退还操作完成');
      setRefundModal(null);
      refundForm.resetFields();
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSaving(false);
    }
  };

  const handleAddInstallment = async () => {
    if (installmentModal == null) return;
    setSaving(true);
    try {
      const values = await installmentForm.validateFields();
      await addInstallmentMutation.mutateAsync({
        id: installmentModal,
        payload: {
          amount: values.amount,
          dueDate: values.dueDate.format('YYYY-MM-DD'),
        },
      });
      message.success('分期已添加');
      setInstallmentModal(null);
      installmentForm.resetFields();
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSaving(false);
    }
  };

  const handlePayInstallment = async (installmentId: number) => {
    try {
      await payInstallmentMutation.mutateAsync(installmentId);
      message.success('分期已标记为已缴');
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const saveInstallmentCell = async (
    installmentId: number,
    field: 'status' | 'paidDate',
    value: unknown,
  ) => {
    try {
      await saveInstallmentCellMutation.mutateAsync({ installmentId, field, value });
      message.success('分期记录已保存');
      if (detailModal) {
        const refreshed = await api.get<DepositRecord>(`/deposits/${detailModal.id}`);
        setDetailModal(refreshed);
      }
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const handleDeleteInstallment = async (installmentId: number) => {
    try {
      await deleteInstallmentMutation.mutateAsync(installmentId);
      message.success('分期已归档');
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const eligibleColumns = [
    {
      title: '学生',
      render: (_: unknown, r: EligibleStudent) =>
        `${r.studentName} (${r.studentNo || `#${r.studentId}`})`,
    },
    {
      title: '房间',
      render: (_: unknown, r: EligibleStudent) =>
        `${r.building ? `${r.building}-` : ''}${r.roomNumber}`,
    },
    { title: '房型', dataIndex: 'roomType' },
    {
      title: '当前押金',
      dataIndex: 'depositAmount',
      render: (v: number) => `¥${Number(v || 0).toFixed(2)}`,
    },
  ];

  return (
    <div>
      <div
        style={{
          marginBottom: 16,
          display: 'flex',
          justifyContent: 'space-between',
          flexWrap: 'wrap',
          gap: 8,
        }}
      >
        <Space wrap>
          <Input.Search
            placeholder="搜索学生姓名/学号"
            allowClear
            style={{ width: 180 }}
            onSearch={(v) => setSearchText(v)}
            onChange={(e) => {
              setSearchText(e.target.value);
            }}
          />
          <Select
            placeholder="房型筛选"
            allowClear
            style={{ width: 130 }}
            value={filterRoomType}
            onChange={changeFilterRoomType}
            options={roomTypeOptions}
          />
          <Select
            placeholder="状态筛选"
            allowClear
            style={{ width: 120 }}
            value={filterStatus}
            disabled={!!filterRoomType}
            onChange={(v) => setFilterStatus(v)}
            options={[
              { value: 'paid', label: '有余额' },
              { value: 'refunded', label: '已全退' },
              { value: 'depleted', label: '已扣完' },
            ]}
          />
        </Space>
        <Space wrap>
          <PermissionButton
            permission="deposit:create"
            icon={<TeamOutlined />}
            onClick={() => openBatchModal()}
          >
            按房型批量收取
          </PermissionButton>
          <PermissionButton
            permission="deposit:create"
            type="primary"
            icon={<PlusOutlined />}
            onClick={openCreateDeposit}
          >
            收取押金
          </PermissionButton>
        </Space>
      </div>
      {isError ? (
        <QueryErrorState
          title="押金数据加载失败"
          description="请检查网络后重试。"
          onRetry={() => void refetch()}
        />
      ) : filterRoomType && eligibleError ? (
        <QueryErrorState
          title="可收取押金的学生加载失败"
          description="请检查网络后重试。"
          onRetry={() => void refetchEligible()}
        />
      ) : (
        <DepositTable
          data={filteredData}
          loading={loading || (!!filterRoomType && eligibleLoading)}
          canPurgeDeposit={canPurgeDeposit}
          canCreateDeposit={hasPermission('deposit:create')}
          onCreateDeposit={openCreateDeposit}
          refundForm={refundForm}
          onDetail={(record) => setDetailModal(record)}
          onRefund={(record) => setRefundModal(record)}
          onArchive={(id) => archiveMutation.mutateAsync(id)}
          onPurge={(id) => purgeMutation.mutateAsync(id)}
        />
      )}
      <DepositModals
        batchModal={batchModal}
        createModal={createModal}
        refundModal={refundModal}
        detailModal={detailModal}
        installmentModal={installmentModal}
        batchForm={batchForm}
        createForm={createForm}
        refundForm={refundForm}
        installmentForm={installmentForm}
        saving={saving}
        batchRoomType={batchRoomType}
        effectiveSelectedEligibleIds={effectiveSelectedEligibleIds}
        eligibleStudents={eligibleStudents}
        eligibleLoading={eligibleLoading}
        eligibleColumns={eligibleColumns}
        studentOptions={studentOptions}
        onBatchRoomTypeChange={handleBatchRoomTypeChange}
        onBatchCreate={handleBatchCreate}
        onCreate={handleCreate}
        onRefund={handleRefund}
        onAddInstallment={handleAddInstallment}
        onPayInstallment={handlePayInstallment}
        onSaveInstallmentCell={saveInstallmentCell}
        onDeleteInstallment={handleDeleteInstallment}
        onCloseBatch={() => setBatchModal(false)}
        onCloseCreate={() => setCreateModal(false)}
        onCloseRefund={() => setRefundModal(null)}
        onCloseDetail={() => setDetailModal(null)}
        onCloseInstallment={() => setInstallmentModal(null)}
        onOpenInstallment={(id) => {
          setInstallmentModal(id);
          installmentForm.resetFields();
        }}
        onSelectEligible={(ids) => {
          setSelectedEligibleStudentIds(ids);
          setSelectionTouched(true);
        }}
      />
    </div>
  );
};

export default DepositsPage;
