// 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 { downloadBlob } from '../../utils/download';
import { message } from '../../ui/app-message';
import { usePermission } from '../../hooks/usePermission';
import { useApiMutation } from '../../hooks/useApiMutation';
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';

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 {
    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,
  } = useQuery<{
    rooms: any[];
    personal: any[];
    students: any[];
    roomsList: any[];
  }>({
    queryKey: ['expenses', showArchived ? 'archived' : 'active'],
    queryFn: async () => {
      try {
        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),
        };
      } catch {
        message.error('加载费用数据失败');
        return { rooms: [], personal: [], students: [], roomsList: [] };
      }
    },
  });
  const roomExpenses = expenseResult.rooms;
  const personalExpenses = expenseResult.personal;
  const students = expenseResult.students;
  const rooms = expenseResult.roomsList;
  const loading = isLoading || isFetching;

  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>
      <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 downloadBlob('/expenses/utility/template', '水电费导入模板.xlsx').catch(
                    () => message.error('下载失败'),
                  );
                }}
                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 downloadBlob('/expenses/personal/template', '个人附加费导入模板.xlsx').catch(
                    () => message.error('下载失败'),
                  );
                }}
                onExport={() => {
                  downloadBlob('/expenses/personal/export', '个人附加费导出.xlsx').catch(() =>
                    message.error('导出失败'),
                  );
                }}
              />
            ),
          },
        ]}
      />

      <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;
