// aislop-ignore-file: duplicate-block -- 表格/表单声明结构相似且参数不同，渲染逻辑已共享组件化
import React, { useState, useMemo, useCallback } from 'react';
import { useQuery } from '@tanstack/react-query';
import { App, Button, Form, Space, Tabs } from 'antd';
import dayjs from 'dayjs';
import api from '../../api';
import { message } from '../../ui/app-message';
import { usePermission } from '../../hooks/usePermission';
import { useApiMutation } from '../../hooks/useApiMutation';
import { useDownload } from '../../hooks/useDownload';
import { validateResponse } from '../../utils/validate';
import {
  expenseLookupsSchema,
  expenseRecordsSchema,
  expenseRoomsListSchema,
  expenseStudentLookupsSchema,
} from '../../api/schemas';
import { archiveViewPolicy, expenseStatusForView } from '../archive-view';
import { ExpenseTablePanel } from './ExpenseTablePanel';
import { PersonalExpenseModal, RoomExpenseModal, UtilityModal } from './ExpenseModals';
import { QueryErrorState } from '../../components/QueryState';
import { useVisibleRefetch } from '../../hooks/usePageVisible';

const ExpensesPage: React.FC = () => {
  const { modal } = App.useApp();
  const { hasPermission } = usePermission();
  const canPurgeExpense = hasPermission('expense:purge');
  const [roomModal, setRoomModal] = useState(false);
  const [personalModal, setPersonalModal] = useState(false);
  const [utilityModal, setUtilityModal] = useState(false);
  const [editingRoom, setEditingRoom] = useState<any>(null);
  const [editingPersonal, setEditingPersonal] = useState<any>(null);
  const [roomForm] = Form.useForm();
  const [personalForm] = Form.useForm();
  const [utilityForm] = Form.useForm();
  const [roomSearch, setRoomSearch] = useState('');
  const [roomTypeFilter, setRoomTypeFilter] = useState<string | undefined>(undefined);
  const [personalSearch, setPersonalSearch] = useState('');
  const [personalTypeFilter, setPersonalTypeFilter] = useState<string | undefined>(undefined);
  const [selectedRoomKeys, setSelectedRoomKeys] = useState<number[]>([]);
  const [selectedPersonalKeys, setSelectedPersonalKeys] = useState<number[]>([]);
  const [saving, setSaving] = useState(false);
  const [batchLoading, setBatchLoading] = useState(false);
  const [showArchived, setShowArchived] = useState(false);
  const expenseViewPolicy = archiveViewPolicy(showArchived ? 'archived' : 'active');

  const { downloading: utilityTemplateDownloading, run: runUtilityTemplateDownload } =
    useDownload();
  const { downloading: personalTemplateDownloading, run: runPersonalTemplateDownload } =
    useDownload();
  const { downloading: personalExportDownloading, run: runPersonalExportDownload } = useDownload();

  const {
    data: typeLookups = { typeOptions: [], personalTypeOptions: [], typeMap: {} },
  } = useQuery<{
    typeOptions: { value: string; label: string }[];
    personalTypeOptions: { value: string; label: string }[];
    typeMap: Record<string, string>;
  }>({
    queryKey: ['expense-lookups'],
    queryFn: async () => {
      try {
        return validateResponse(expenseLookupsSchema, await api.get('/expenses/lookups'));
      } catch {
        return { typeOptions: [], personalTypeOptions: [], typeMap: {} };
      }
    },
  });
  const { typeOptions, personalTypeOptions, typeMap } = typeLookups;

  const {
    data: expenseResult = { rooms: [], personal: [], students: [], roomsList: [] },
    isLoading,
    isFetching,
    isError,
    refetch,
  } = useQuery<{
    rooms: any[];
    personal: any[];
    students: any[];
    roomsList: any[];
  }>({
    queryKey: ['expenses', showArchived ? 'archived' : 'active'],
    queryFn: async () => {
      const [rooms, personal, students, roomsList] = await Promise.all([
        api.get('/expenses/room', {
          params: { status: expenseStatusForView(showArchived ? 'archived' : 'active') },
        }),
        api.get('/expenses/personal', {
          params: { status: expenseStatusForView(showArchived ? 'archived' : 'active') },
        }),
        api.get('/expenses/student-lookups'),
        api.get('/rooms'),
      ]);
      return {
        rooms: validateResponse(expenseRecordsSchema, rooms),
        personal: validateResponse(expenseRecordsSchema, personal),
        students: validateResponse(expenseStudentLookupsSchema, students),
        roomsList: validateResponse(expenseRoomsListSchema, roomsList),
      };
    },
  });
  const roomExpenses = expenseResult.rooms;
  const personalExpenses = expenseResult.personal;
  const students = expenseResult.students;
  const rooms = expenseResult.roomsList;
  const loading = isLoading || isFetching;
  // RouteKeeper 保活页面切回时刷新费用列表
  useVisibleRefetch(['expenses']);

  const mutations = {
    saveRoom: useApiMutation(
      async (payload: Record<string, unknown>) =>
        editingRoom
          ? api.put(`/expenses/room/${editingRoom.id}`, payload)
          : api.post('/expenses/room', payload),
      { invalidate: [['expenses']] },
    ),
    saveRoomCell: useApiMutation(
      async ({ record, field, value }: { record: any; field: string; value: unknown }) =>
        api.put(`/expenses/room/${record.id}`, { [field]: value }),
      { invalidate: [['expenses']] },
    ),
    savePersonal: useApiMutation(
      async (payload: Record<string, unknown>) =>
        editingPersonal
          ? api.put(`/expenses/personal/${editingPersonal.id}`, payload)
          : api.post('/expenses/personal', payload),
      { invalidate: [['expenses']] },
    ),
    savePersonalCell: useApiMutation(
      async ({ record, field, value }: { record: any; field: string; value: unknown }) =>
        api.put(`/expenses/personal/${record.id}`, { [field]: value }),
      { invalidate: [['expenses']] },
    ),
    period: useApiMutation(
      async ({ id, periodStart, periodEnd }: { id: number; periodStart: string; periodEnd: string }) =>
        api.put(`/expenses/room/${id}`, { periodStart, periodEnd }),
      { invalidate: [['expenses']] },
    ),
    utility: useApiMutation(
      async (payload: Record<string, unknown>) => api.post('/expenses/student-utility', payload),
      { invalidate: [['expenses'], ['bills']] },
    ),
    importUtility: useApiMutation(
      async (formData: FormData) =>
        api.post('/expenses/utility/import', formData),
      { invalidate: [['expenses']] },
    ),
    importPersonal: useApiMutation(
      async (formData: FormData) =>
        api.post('/expenses/personal/import', formData),
      { invalidate: [['expenses']] },
    ),
    archiveRoom: useApiMutation(
      async (id: number) => api.delete(`/expenses/room/${id}`),
      { invalidate: [['expenses']] },
    ),
    archivePersonal: useApiMutation(
      async (id: number) => api.delete(`/expenses/personal/${id}`),
      { invalidate: [['expenses']] },
    ),
    batchDeleteRoom: useApiMutation(
      async (ids: number[]) => api.post('/expenses/room/batch-delete', { ids }),
      { invalidate: [['expenses']] },
    ),
    batchDeletePersonal: useApiMutation(
      async (ids: number[]) => api.post('/expenses/personal/batch-delete', { ids }),
      { invalidate: [['expenses']] },
    ),
    batchRestoreRoom: useApiMutation(
      async (ids: number[]) => api.put('/expenses/room/batch-restore', { ids }),
      { invalidate: [['expenses']] },
    ),
    batchRestorePersonal: useApiMutation(
      async (ids: number[]) => api.put('/expenses/personal/batch-restore', { ids }),
      { invalidate: [['expenses']] },
    ),
    purgeRoom: useApiMutation(
      async (id: number) => api.delete(`/expenses/room/${id}/permanent`),
      { invalidate: [['expenses']] },
    ),
    purgePersonal: useApiMutation(
      async (id: number) => api.delete(`/expenses/personal/${id}/permanent`),
      { invalidate: [['expenses']] },
    ),
  };

  const handleBatchDeleteRoom = async () => {
    setBatchLoading(true);
    try {
      await mutations.batchDeleteRoom.mutateAsync(selectedRoomKeys);
      message.success('批量归档成功');
      setSelectedRoomKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchDeletePersonal = async () => {
    setBatchLoading(true);
    try {
      await mutations.batchDeletePersonal.mutateAsync(selectedPersonalKeys);
      message.success('批量归档成功');
      setSelectedPersonalKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchRestoreRoom = async () => {
    setBatchLoading(true);
    try {
      await mutations.batchRestoreRoom.mutateAsync(selectedRoomKeys);
      message.success('批量恢复成功');
      setSelectedRoomKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchRestorePersonal = async () => {
    setBatchLoading(true);
    try {
      await mutations.batchRestorePersonal.mutateAsync(selectedPersonalKeys);
      message.success('批量恢复成功');
      setSelectedPersonalKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handlePurgeRoom = (id: number) => {
    modal.confirm({
      title: '永久删除宿舍费用？',
      content: '删除后不可恢复。确定继续？',
      okText: '永久删除',
      okButtonProps: { danger: true },
      cancelText: '取消',
      onOk: async () => {
        try {
          await mutations.purgeRoom.mutateAsync(id);
          message.success('已永久删除');
        } catch {
          // 错误提示由 useApiMutation 统一处理
        }
      },
    });
  };

  const handlePurgePersonal = (id: number) => {
    modal.confirm({
      title: '永久删除个人费用？',
      content: '删除后不可恢复。确定继续？',
      okText: '永久删除',
      okButtonProps: { danger: true },
      cancelText: '取消',
      onOk: async () => {
        try {
          await mutations.purgePersonal.mutateAsync(id);
          message.success('已永久删除');
        } catch {
          // 错误提示由 useApiMutation 统一处理
        }
      },
    });
  };

  const handleBatchPurgeRoom = async () => {
    setBatchLoading(true);
    try {
      await Promise.all(selectedRoomKeys.map((id) => mutations.purgeRoom.mutateAsync(id)));
      message.success('批量永久删除成功');
      setSelectedRoomKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchPurgePersonal = async () => {
    setBatchLoading(true);
    try {
      await Promise.all(selectedPersonalKeys.map((id) => mutations.purgePersonal.mutateAsync(id)));
      message.success('批量永久删除成功');
      setSelectedPersonalKeys([]);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setBatchLoading(false);
    }
  };

  const changeArchiveView = (archived: boolean) => {
    setShowArchived(archived);
    setSelectedRoomKeys([]);
    setSelectedPersonalKeys([]);
  };

  const filteredRoomExpenses = useMemo(() => {
    return roomExpenses.filter((r: any) => {
      if (roomSearch) {
        const s = roomSearch.toLowerCase();
        if (!r.room?.roomNumber?.toLowerCase().includes(s)) return false;
      }
      if (roomTypeFilter && r.expenseType !== roomTypeFilter) return false;
      return true;
    });
  }, [roomExpenses, roomSearch, roomTypeFilter]);

  const filteredPersonalExpenses = useMemo(() => {
    return personalExpenses.filter((r: any) => {
      if (personalSearch) {
        const s = personalSearch.toLowerCase();
        if (!r.student?.name?.toLowerCase().includes(s)) return false;
      }
      if (personalTypeFilter && r.expenseType !== personalTypeFilter) return false;
      return true;
    });
  }, [personalExpenses, personalSearch, personalTypeFilter]);

  const handleRoomExpense = async () => {
    setSaving(true);
    try {
      const values = await roomForm.validateFields();
      const payload = {
        roomId: values.roomId,
        expenseType: values.expenseType,
        amount: values.amount,
        periodStart: values.period[0].format('YYYY-MM-DD'),
        periodEnd: values.period[1].format('YYYY-MM-DD'),
        description: values.description,
      };
      await mutations.saveRoom.mutateAsync(payload);
      message.success(editingRoom ? '更新成功' : '录入成功');
      setRoomModal(false);
      setEditingRoom(null);
      roomForm.resetFields();
    } catch {
      // 校验错误静默，接口错误由 useApiMutation 统一提示
    } finally {
      setSaving(false);
    }
  };

  const handleStudentUtility = async () => {
    const values = await utilityForm.validateFields();
    setSaving(true);
    try {
      const result: any = await mutations.utility.mutateAsync({
        studentId: values.studentId,
        expenseType: values.expenseType,
        amount: values.amount,
        periodStart: values.period[0].format('YYYY-MM-DD'),
        periodEnd: values.period[1].format('YYYY-MM-DD'),
        description: values.description,
      });
      const bill = result.bill;
      message.success(
        `账单已生成，已从余额扣除 ¥${Number(bill.paidAmount || 0).toFixed(2)}，待补缴 ¥${Number(bill.outstandingAmount || 0).toFixed(2)}`,
      );
      setUtilityModal(false);
      utilityForm.resetFields();
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSaving(false);
    }
  };

  const handlePersonalExpense = async () => {
    setSaving(true);
    try {
      const values = await personalForm.validateFields();
      const payload = {
        studentId: values.studentId,
        roomId: values.roomId,
        expenseType: values.expenseType,
        amount: values.amount,
        expenseDate: values.expenseDate.format('YYYY-MM-DD'),
        description: values.description,
      };
      await mutations.savePersonal.mutateAsync(payload);
      message.success(editingPersonal ? '更新成功' : '录入成功');
      setPersonalModal(false);
      setEditingPersonal(null);
      personalForm.resetFields();
    } catch {
      // 校验错误静默，接口错误由 useApiMutation 统一提示
    } finally {
      setSaving(false);
    }
  };

  const openEditRoom = (record: any) => {
    setEditingRoom(record);
    roomForm.setFieldsValue({
      roomId: record.roomId,
      expenseType: record.expenseType,
      amount: Number(record.amount),
      period: record.periodStart ? [dayjs(record.periodStart), dayjs(record.periodEnd)] : undefined,
      description: record.description,
    });
    setRoomModal(true);
  };

  const openEditPersonal = (record: any) => {
    setEditingPersonal(record);
    personalForm.setFieldsValue({
      studentId: record.studentId,
      roomId: record.roomId,
      expenseType: record.expenseType,
      amount: Number(record.amount),
      expenseDate: record.expenseDate ? dayjs(record.expenseDate) : undefined,
      description: record.description,
    });
    setPersonalModal(true);
  };

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

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

  return (
    <div>
      <Space style={{ marginBottom: 16 }}>
        <Button
          type={!showArchived ? 'primary' : 'default'}
          onClick={() => changeArchiveView(false)}
        >
          正常费用
        </Button>
        <Button type={showArchived ? 'primary' : 'default'} onClick={() => changeArchiveView(true)}>
          已归档费用
        </Button>
      </Space>
      {isError ? (
        <QueryErrorState
          title="费用数据加载失败"
          description="请检查网络后重试。"
          onRetry={() => void refetch()}
        />
      ) : (
        <Tabs
          items={[
            {
              key: 'room',
              label: '宿舍费用',
              children: (
                <ExpenseTablePanel
                  kind="room"
                  searchText={roomSearch}
                  onSearchChange={setRoomSearch}
                  typeFilter={roomTypeFilter}
                  onTypeFilterChange={setRoomTypeFilter}
                  typeOptions={typeOptions}
                  typeMap={typeMap}
                  data={filteredRoomExpenses}
                  loading={loading}
                  selectedKeys={selectedRoomKeys}
                  onSelect={setSelectedRoomKeys}
                  rooms={rooms}
                  students={students}
                  readonly={expenseViewPolicy.readonly}
                  showArchived={showArchived}
                  canPurgeExpense={canPurgeExpense}
                  batchLoading={batchLoading}
                  canImport={hasPermission('expense:create')}
                  onBatchRestore={handleBatchRestoreRoom}
                  onBatchPurge={handleBatchPurgeRoom}
                  onBatchDelete={handleBatchDeleteRoom}
                  onSaveCell={saveRoomCell}
                  onPeriodSave={async (id, periodStart, periodEnd) => {
                    try {
                      await mutations.period.mutateAsync({ id, periodStart, periodEnd });
                      message.success('已保存');
                    } catch {
                      // 错误提示由 useApiMutation 统一处理
                    }
                  }}
                  onEdit={openEditRoom}
                  onArchive={(id) => mutations.archiveRoom.mutateAsync(id)}
                  onPurge={handlePurgeRoom}
                  onImport={(formData) => mutations.importUtility.mutateAsync(formData)}
                  onTemplateDownload={() => {
                    void runUtilityTemplateDownload('/expenses/utility/template', '水电费导入模板.xlsx', {
                      successMsg: '模板已下载',
                      errorMsg: '下载失败',
                    });
                  }}
                  templateLoading={utilityTemplateDownloading}
                  onAddUtility={() => setUtilityModal(true)}
                />
              ),
            },
            {
              key: 'personal',
              label: '个人附加费',
              children: (
                <ExpenseTablePanel
                  kind="personal"
                  searchText={personalSearch}
                  onSearchChange={setPersonalSearch}
                  typeFilter={personalTypeFilter}
                  onTypeFilterChange={setPersonalTypeFilter}
                  typeOptions={personalTypeOptions}
                  typeMap={typeMap}
                  data={filteredPersonalExpenses}
                  loading={loading}
                  selectedKeys={selectedPersonalKeys}
                  onSelect={setSelectedPersonalKeys}
                  rooms={rooms}
                  students={students}
                  readonly={expenseViewPolicy.readonly}
                  showArchived={showArchived}
                  canPurgeExpense={canPurgeExpense}
                  batchLoading={batchLoading}
                  canImport={hasPermission('expense:create')}
                  onBatchRestore={handleBatchRestorePersonal}
                  onBatchPurge={handleBatchPurgePersonal}
                  onBatchDelete={handleBatchDeletePersonal}
                  onSaveCell={savePersonalCell}
                  onPeriodSave={async () => undefined}
                  onEdit={openEditPersonal}
                  onArchive={(id) => mutations.archivePersonal.mutateAsync(id)}
                  onPurge={handlePurgePersonal}
                  onImport={(formData) => mutations.importPersonal.mutateAsync(formData)}
                  onTemplateDownload={() => {
                    void runPersonalTemplateDownload('/expenses/personal/template', '个人附加费导入模板.xlsx', {
                      successMsg: '模板已下载',
                      errorMsg: '下载失败',
                    });
                  }}
                  templateLoading={personalTemplateDownloading}
                  onExport={() => {
                    void runPersonalExportDownload('/expenses/personal/export', '个人附加费导出.xlsx', {
                      successMsg: '导出成功',
                      errorMsg: '导出失败',
                    });
                  }}
                  exportLoading={personalExportDownloading}
                />
              ),
            },
          ]}
        />
      )}

      <RoomExpenseModal
        open={roomModal}
        editing={!!editingRoom}
        saving={saving}
        form={roomForm}
        rooms={rooms}
        typeOptions={typeOptions}
        onOk={handleRoomExpense}
        onCancel={() => {
          setRoomModal(false);
          setEditingRoom(null);
        }}
      />
      <UtilityModal
        open={utilityModal}
        saving={saving}
        form={utilityForm}
        students={students}
        onOk={handleStudentUtility}
        onCancel={() => setUtilityModal(false)}
      />
      <PersonalExpenseModal
        open={personalModal}
        editing={!!editingPersonal}
        saving={saving}
        form={personalForm}
        students={students}
        rooms={rooms}
        personalTypeOptions={personalTypeOptions}
        onOk={handlePersonalExpense}
        onCancel={() => {
          setPersonalModal(false);
          setEditingPersonal(null);
        }}
      />
    </div>
  );
};

export default ExpensesPage;
