// aislop-ignore-file: duplicate-block -- 表格/表单声明结构相似且参数不同，渲染逻辑已共享组件化
import React, { useState, useMemo, useCallback } from 'react';
import { useQuery } from '@tanstack/react-query';
import { validateResponse } from '../../utils/validate';
import { roomsOverviewSchema } from '../../api/schemas';
import {
  App,
  Form,
} from 'antd';
import type { UploadRequestOption } from '@rc-component/upload/lib/interface';
import api from '../../api';
import { downloadBlob } from '../../utils/download';
import { message } from '../../ui/app-message';
import { usePermission } from '../../hooks/usePermission';
import { useVisibleRefetch } from '../../hooks/usePageVisible';
import { selectArchiveRecords } from '../archive-view';
import { getErrorMessage } from '../../utils/error';
import { QueryErrorState } from '../../components/QueryState';
import { useRoomColumns, type BedItem, type LockerItem } from './RoomColumns';
import { RoomDetailArea } from './RoomModals';
import { RoomsToolbar } from './RoomsToolbar';
import { RoomsTable } from './RoomsTable';
import { useRoomItemMutations, useRoomMutations } from './useRoomMutations';

const RoomsPage: React.FC = () => {
  const { modal } = App.useApp();
  const { hasPermission, permissionsReady } = usePermission();
  const canEditRooms = permissionsReady && hasPermission('room:edit');
  const canCreateRooms = permissionsReady && hasPermission('room:create');
  const canDeleteRooms = permissionsReady && hasPermission('room:delete');
  const canPurgeRooms = permissionsReady && hasPermission('room:purge');
  const [modalOpen, setModalOpen] = useState(false);
  const [editing, setEditing] = useState<any>(null);
  const canSaveRoom = editing ? canEditRooms : canCreateRooms;
  const [showArchived, setShowArchived] = useState(false);
  const [searchText, setSearchText] = useState('');
  const [filterBuilding, setFilterBuilding] = useState<string | undefined>(undefined);
  const [filterStatus, setFilterStatus] = useState<string | undefined>(undefined);
  const [filterRentalCategory, setFilterRentalCategory] = useState<string | undefined>(undefined);
  const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
  const [saving, setSaving] = useState(false);
  const [form] = Form.useForm();
  const [drawerOpen, setDrawerOpen] = useState(false);
  const [drawerRoom, setDrawerRoom] = useState<any>(null);
  const [beds, setBeds] = useState<BedItem[]>([]);
  const [lockers, setLockers] = useState<LockerItem[]>([]);
  const [bedModalOpen, setBedModalOpen] = useState(false);
  const [bedEditing, setBedEditing] = useState<any>(null);
  const [lockerModalOpen, setLockerModalOpen] = useState(false);
  const [lockerEditing, setLockerEditing] = useState<any>(null);
  const [bedForm] = Form.useForm();
  const [lockerForm] = Form.useForm();
  const [savingBed, setSavingBed] = useState(false);
  const [savingLocker, setSavingLocker] = useState(false);
  const [batchLoading, setBatchLoading] = useState(false);
  const [bedsError, setBedsError] = useState(false);
  const [lockersError, setLockersError] = useState(false);

  const {
    data = [],
    isLoading,
    isFetching,
    isError,
    refetch,
  } = useQuery<any[]>({
    queryKey: ['rooms', 'overview', showArchived],
    queryFn: async () => {
      const params: any = { includeArchived: showArchived ? 'true' : undefined };
      const res: any = await api.get('/rooms/overview', { params });
      return selectArchiveRecords(
        validateResponse<any[]>(roomsOverviewSchema, res),
        showArchived ? 'archived' : 'active',
      );
    },
  });
  const loading = isLoading || isFetching;
  // RouteKeeper 保活页面切回时刷新列表，避免看到陈旧数据
  useVisibleRefetch(['rooms']);

  const {
    saveMutation,
    saveRoomCellMutation,
    archiveMutation,
    restoreMutation,
    purgeMutation,
    batchDeleteMutation,
    batchRestoreMutation,
    batchPurgeMutation,
    importMutation,
  } = useRoomMutations(editing);
  const {
    saveBedCellMutation,
    saveLockerCellMutation,
    saveBedMutation,
    deleteBedMutation,
    batchBedsMutation,
    saveLockerMutation,
    deleteLockerMutation,
    batchLockersMutation,
  } = useRoomItemMutations();

  const handleBatchDelete = useCallback(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);
    }
  }, [batchLoading, batchDeleteMutation, selectedRowKeys]);

  const handleBatchRestore = useCallback(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);
    }
  }, [batchLoading, batchRestoreMutation, selectedRowKeys]);

  const buildings = useMemo(() => {
    const set = new Set(data.flatMap((r: any) => (r.building ? [r.building] : [])));
    return [...set].sort();
  }, [data]);

  const filteredData = useMemo(() => {
    let result = data;
    if (searchText) {
      const keyword = searchText.toLowerCase();
      result = result.filter(
        (r: Record<string, unknown>) =>
          typeof r.roomNumber === 'string' && r.roomNumber.toLowerCase().includes(keyword),
      );
    }
    if (filterBuilding)
      result = result.filter((r: Record<string, unknown>) => r.building === filterBuilding);
    if (filterStatus)
      result = result.filter((r: Record<string, unknown>) => r.status === filterStatus);
    if (filterRentalCategory) {
      result = result.filter(
        (r: Record<string, unknown>) => r.rentalCategory === filterRentalCategory,
      );
    }
    return result;
  }, [data, searchText, filterBuilding, filterStatus, filterRentalCategory]);
  const remainingBedSlots = useMemo(() => {
    const capacity = Number(drawerRoom?.capacity) || 0;
    return Math.max(capacity - beds.length, 0);
  }, [drawerRoom?.capacity, beds.length]);
  const defaultBatchBedCount = Math.min(4, Math.max(remainingBedSlots, 1));

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

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

  const saveBedCell = async (record: BedItem, field: string, value: unknown) => {
    if (!drawerRoom) return;
    try {
      await saveBedCellMutation.mutateAsync({
        roomId: drawerRoom.id,
        bedId: record.id,
        field,
        value,
      });
      message.success('已保存');
      await fetchBeds(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const saveLockerCell = async (record: LockerItem, field: string, value: unknown) => {
    if (!drawerRoom) return;
    try {
      await saveLockerCellMutation.mutateAsync({
        roomId: drawerRoom.id,
        lockerId: record.id,
        field,
        value,
      });
      message.success('已保存');
      await fetchLockers(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const fetchBeds = useCallback(async (roomId: number) => {
    try {
      const res = await api.get<BedItem[]>(`/rooms/${roomId}/beds`);
      setBeds(res);
      setBedsError(false);
    } catch (e: unknown) {
      setBedsError(true);
      message.error(getErrorMessage(e, '加载床位失败'));
    }
  }, []);

  const fetchLockers = useCallback(async (roomId: number) => {
    try {
      const res = await api.get<LockerItem[]>(`/rooms/${roomId}/lockers`);
      setLockers(res);
      setLockersError(false);
    } catch (e: unknown) {
      setLockersError(true);
      message.error(getErrorMessage(e, '加载柜子失败'));
    }
  }, []);

  const handleSaveBed = async () => {
    if (!drawerRoom) return;
    const values = await bedForm.validateFields();
    setSavingBed(true);
    try {
      await saveBedMutation.mutateAsync({
        roomId: drawerRoom.id,
        bedId: bedEditing?.id,
        values,
      });
      message.success(bedEditing ? '更新成功' : '添加成功');
      setBedModalOpen(false);
      bedForm.resetFields();
      setBedEditing(null);
      await fetchBeds(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSavingBed(false);
    }
  };

  const handleDeleteBed = async (id: number) => {
    if (!drawerRoom) return;
    try {
      await deleteBedMutation.mutateAsync({ roomId: drawerRoom.id, bedId: id });
      message.success('已归档');
      await fetchBeds(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const handleBatchBeds = async (count: number) => {
    if (!drawerRoom) return;
    try {
      await batchBedsMutation.mutateAsync({ roomId: drawerRoom.id, count });
      message.success(`已生成 ${count} 张床位`);
      await fetchBeds(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const handleSaveLocker = async () => {
    if (!drawerRoom) return;
    const values = await lockerForm.validateFields();
    setSavingLocker(true);
    try {
      await saveLockerMutation.mutateAsync({
        roomId: drawerRoom.id,
        lockerId: lockerEditing?.id,
        values,
      });
      message.success(lockerEditing ? '更新成功' : '添加成功');
      setLockerModalOpen(false);
      lockerForm.resetFields();
      setLockerEditing(null);
      await fetchLockers(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    } finally {
      setSavingLocker(false);
    }
  };

  const handleDeleteLocker = async (id: number) => {
    if (!drawerRoom) return;
    try {
      await deleteLockerMutation.mutateAsync({ roomId: drawerRoom.id, lockerId: id });
      message.success('已归档');
      await fetchLockers(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  const handleBatchLockers = async (count: number) => {
    if (!drawerRoom) return;
    try {
      await batchLockersMutation.mutateAsync({ roomId: drawerRoom.id, count });
      message.success(`已生成 ${count} 个柜子`);
      await fetchLockers(drawerRoom.id);
    } catch {
      // 错误提示由 useApiMutation 统一处理
    }
  };

  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, roomNumber: string) => {
      modal.confirm({
        title: `永久删除宿舍「${roomNumber}」？`,
        content: '删除后不可恢复，该宿舍及其床位、柜子、查寝记录将无法找回。确定继续？',
        okText: '永久删除',
        okButtonProps: { danger: true },
        cancelText: '取消',
        onOk: async () => {
          try {
            await purgeMutation.mutateAsync(id);
            message.success('已永久删除（不可恢复）');
          } catch {
            // 错误提示由 useApiMutation 统一处理
          }
        },
      });
    },
    [modal, purgeMutation],
  );

  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 = () => {
    downloadBlob('/rooms/template', '房间导入模板.xlsx').catch(() => message.error('下载失败'));
  };

  const handleExport = () => {
    const params = showArchived ? '?includeArchived=true' : '';
    downloadBlob('/rooms/export' + params, '房间列表.xlsx').catch(() =>
      message.error('导出失败'),
    );
  };

  const columns = useRoomColumns({
    canEditRooms,
    canDeleteRooms,
    canPurgeRooms,
    onSaveRoomCell: saveRoomCell,
    onRestore: handleRestore,
    onArchive: handleArchive,
    onPurge: handlePurge,
    onView: (record) => {
      setDrawerRoom(record);
      setDrawerOpen(true);
      void Promise.all([fetchBeds(record.id), fetchLockers(record.id)]);
    },
    onEdit: (record) => {
      setEditing(record);
      form.setFieldsValue(record);
      setModalOpen(true);
    },
  });

  return (
    <div>
      <RoomsToolbar
        onSearch={setSearchText}
        buildings={buildings}
        filterBuilding={filterBuilding}
        onFilterBuilding={setFilterBuilding}
        filterStatus={filterStatus}
        onFilterStatus={setFilterStatus}
        filterRentalCategory={filterRentalCategory}
        onFilterRentalCategory={setFilterRentalCategory}
        showArchived={showArchived}
        onToggleArchived={() => {
          setShowArchived(!showArchived);
          setFilterStatus(undefined);
          setSelectedRowKeys([]);
        }}
        selectedRowKeys={selectedRowKeys}
        batchLoading={batchLoading}
        canEditRooms={canEditRooms}
        canPurgeRooms={canPurgeRooms}
        canDeleteRooms={canDeleteRooms}
        hasCreatePermission={hasPermission('room:create')}
        onBatchRestore={handleBatchRestore}
        onBatchPurge={handleBatchPurge}
        onBatchDelete={handleBatchDelete}
        onAddRoom={() => {
          setEditing(null);
          form.resetFields();
          setModalOpen(true);
        }}
        onImport={async (options: UploadRequestOption<{ message?: string }>) => {
          const { file, onSuccess, onError } = options;
          if (typeof file === 'string') {
            message.error('不支持字符串文件');
            return;
          }
          try {
            const formData = new FormData();
            formData.append('file', file);
            const res = await importMutation.mutateAsync(formData);
            message.success(res.message || '导入成功');
            onSuccess?.(res);
          } catch (e) {
            onError?.(e as Error);
          }
        }}
        onDownloadTemplate={handleDownloadTemplate}
        onExport={handleExport}
      />

      {isError ? (
        <QueryErrorState
          title="宿舍列表加载失败"
          description="请检查网络后重试。"
          onRetry={() => void refetch()}
        />
      ) : (
        <RoomsTable
          columns={columns}
          data={filteredData}
          loading={loading}
          selectedRowKeys={selectedRowKeys}
          onSelect={setSelectedRowKeys}
        />
      )}

      <RoomDetailArea
        modalOpen={modalOpen}
        canSaveRoom={canSaveRoom}
        editing={!!editing}
        saving={saving}
        form={form}
        onSaveRoom={handleSave}
        onCloseRoomModal={() => {
          setModalOpen(false);
          setEditing(null);
        }}
        drawerOpen={drawerOpen}
        drawerRoom={drawerRoom}
        beds={beds}
        lockers={lockers}
        bedsError={bedsError}
        lockersError={lockersError}
        onRetryBeds={() => {
          if (drawerRoom) void fetchBeds(drawerRoom.id);
        }}
        onRetryLockers={() => {
          if (drawerRoom) void fetchLockers(drawerRoom.id);
        }}
        canEditRooms={canEditRooms}
        remainingBedSlots={remainingBedSlots}
        defaultBatchBedCount={defaultBatchBedCount}
        onCloseDrawer={() => {
          setDrawerOpen(false);
          setDrawerRoom(null);
        }}
        onAddBed={() => {
          setBedEditing(null);
          bedForm.resetFields();
          setBedModalOpen(true);
        }}
        onBatchBeds={handleBatchBeds}
        onEditBed={(r) => {
          setBedEditing(r);
          bedForm.setFieldsValue(r);
          setBedModalOpen(true);
        }}
        onDeleteBed={handleDeleteBed}
        onSaveBedCell={saveBedCell}
        onAddLocker={() => {
          setLockerEditing(null);
          lockerForm.resetFields();
          setLockerModalOpen(true);
        }}
        onBatchLockers={handleBatchLockers}
        onEditLocker={(r) => {
          setLockerEditing(r);
          lockerForm.setFieldsValue(r);
          setLockerModalOpen(true);
        }}
        onDeleteLocker={handleDeleteLocker}
        onSaveLockerCell={saveLockerCell}
        bedModalOpen={bedModalOpen}
        bedEditing={!!bedEditing}
        savingBed={savingBed}
        bedForm={bedForm}
        onSaveBed={handleSaveBed}
        onCloseBedModal={() => {
          setBedModalOpen(false);
          setBedEditing(null);
        }}
        lockerModalOpen={lockerModalOpen}
        lockerEditing={!!lockerEditing}
        savingLocker={savingLocker}
        lockerForm={lockerForm}
        onSaveLocker={handleSaveLocker}
        onCloseLockerModal={() => {
          setLockerModalOpen(false);
          setLockerEditing(null);
        }}
      />
    </div>
  );
};

export default RoomsPage;
