import React, { useEffect, useState, useMemo, useCallback } from 'react';
import {
  Table,
  Button,
  Modal,
  Form,
  Select,
  DatePicker,
  Input,
  InputNumber,
  Space,
  Tag,
  Popconfirm,
  Upload,
  Switch,
  Tooltip,
  Empty,
  Alert,
} from 'antd';
import {
  PlusOutlined,
  SwapOutlined,
  LogoutOutlined,
  InboxOutlined,
  UploadOutlined,
  DownloadOutlined,
  ExportOutlined,
} from '@ant-design/icons';
import dayjs, { type Dayjs } from 'dayjs';
import api from '../../api';
import { downloadBlob } from '../../utils/download';
import { maskPhone, maskIdNumber } from '../../utils/sensitive';
import PermissionButton from '../../components/PermissionButton';
import { message } from '../../ui/app-message';
import { buildCheckInPayload, buildTransferPayload } from './occupancy-form';

const { RangePicker } = DatePicker;

const OccupanciesPage: React.FC = () => {
  const [data, setData] = useState<any[]>([]);
  const [students, setStudents] = useState<any[]>([]);
  const [rooms, setRooms] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [checkInModal, setCheckInModal] = useState(false);
  const [checkOutModal, setCheckOutModal] = useState<any>(null);
  const [transferModal, setTransferModal] = useState<any>(null);
  const [showActive, setShowActive] = useState(true);
  const [autoDeposit, setAutoDeposit] = useState(true);
  const [depositAmount, setDepositAmount] = useState(500);
  const [searchText, setSearchText] = useState('');
  const [dateRange, setDateRange] = useState<[dayjs.Dayjs | null, dayjs.Dayjs | null] | null>(null);
  const [batchCheckOutModal, setBatchCheckOutModal] = useState(false);
  const [selectedRowKeys, setSelectedRowKeys] = useState<number[]>([]);
  const [saving, setSaving] = useState(false);
  const [batchLoading, setBatchLoading] = useState(false);
  const [checkInForm] = Form.useForm();
  const [checkOutForm] = Form.useForm();
  const [transferForm] = Form.useForm();
  const [batchCheckOutForm] = Form.useForm();
  const [availableBeds, setAvailableBeds] = useState<any[]>([]);
  const [availableLockers, setAvailableLockers] = useState<any[]>([]);
  const [availableResourcesLoading, setAvailableResourcesLoading] = useState(false);
  const [transferAvailableBeds, setTransferAvailableBeds] = useState<any[]>([]);
  const [transferAvailableLockers, setTransferAvailableLockers] = useState<any[]>([]);
  const [transferResourcesLoading, setTransferResourcesLoading] = useState(false);
  const selectedCheckInRoomId = Form.useWatch('roomId', checkInForm);
  const selectedTransferRoomId = Form.useWatch('newRoomId', transferForm);

  const activeOccupancyByStudentId = useMemo(() => {
    const map = new Map<number, any>();
    data.forEach((item) => {
      if (!item.checkOutDate && item.status !== 'archived') map.set(item.studentId, item);
    });
    return map;
  }, [data]);

  const isRoomSelectable = useCallback((room: any) => {
    const currentCount = Number(room.currentCount || 0);
    const capacity = Number(room.capacity || 0);
    return room.status !== 'archived' && room.status !== 'maintenance' && currentCount < capacity;
  }, []);

  const roomOptionLabel = useCallback((room: any) => {
    const base = `${room.roomNumber} (${room.building || ''}) [${room.currentCount}/${room.capacity}]`;
    if (room.status === 'maintenance') return `${base} · 维修中`;
    if (room.status === 'archived') return `${base} · 已归档`;
    if (Number(room.currentCount || 0) >= Number(room.capacity || 0)) return `${base} · 已满`;
    return base;
  }, []);

  const selectedBatchRecords = useMemo(
    () => data.filter((item) => selectedRowKeys.includes(item.id) && !item.checkOutDate),
    [data, selectedRowKeys],
  );
  const latestSelectedCheckInDate = useMemo(
    () => selectedBatchRecords.map((item) => item.checkInDate).filter(Boolean).sort().at(-1),
    [selectedBatchRecords],
  );
  const latestSelectedBillingStartDate = useMemo(
    () =>
      selectedBatchRecords
        .map((item) => item.billingStartDate || item.checkInDate)
        .filter(Boolean)
        .sort()
        .at(-1),
    [selectedBatchRecords],
  );

  const dateNotBefore = (start: string | Dayjs | null | undefined, messageText: string) =>
    (_: unknown, value?: Dayjs | null) => {
      if (!value || !start) return Promise.resolve();
      const startDate = dayjs.isDayjs(start) ? start : dayjs(start);
      return value.isBefore(startDate, 'day')
        ? Promise.reject(new Error(messageText))
        : Promise.resolve();
    };

  const fetchData = useCallback(async () => {
    setLoading(true);
    try {
      const [occRes, stuRes, rmRes] = (await Promise.allSettled([
        api.get('/occupancies', {
          params: {
            active: showActive ? 'true' : undefined,
            dateFrom: dateRange?.[0]?.format('YYYY-MM-DD'),
            dateTo: dateRange?.[1]?.format('YYYY-MM-DD'),
          },
        }),
        api.get('/students/basic-lookups'),
        api.get('/rooms/overview'),
      ])) as PromiseSettledResult<any>[];
      const labels = ['入住数据', '学生列表', '房间列表'];
      [occRes, stuRes, rmRes].forEach((res, i) => {
        if (res.status === 'rejected') {
          message.warning(`${labels[i]}加载失败`);
        }
      });
      setData(occRes.status === 'fulfilled' ? occRes.value : []);
      setStudents(stuRes.status === 'fulfilled' ? stuRes.value : []);
      setRooms(rmRes.status === 'fulfilled' ? rmRes.value : []);
    } catch (e) {
      console.error(e);
      message.error('数据加载异常');
    }
    setLoading(false);
  }, [showActive, dateRange]);

  useEffect(() => {
    fetchData();
    setSelectedRowKeys([]);
  }, [fetchData]);

  const handleRoomChange = async (roomId: number) => {
    checkInForm.setFieldValue('bedId', undefined);
    checkInForm.setFieldValue('lockerId', undefined);
    setAvailableBeds([]);
    setAvailableLockers([]);
    if (!roomId) return;

    setAvailableResourcesLoading(true);
    try {
      const [beds, lockers] = await Promise.all([
        api.get<any[]>(`/rooms/${roomId}/beds/available`),
        api.get<any[]>(`/rooms/${roomId}/lockers/available`),
      ]);
      setAvailableBeds(beds);
      setAvailableLockers(lockers);
      if (beds.length === 1) checkInForm.setFieldValue('bedId', beds[0].id);
      if (beds.length === 0) message.warning('该宿舍暂无可用床位，请先在宿舍详情添加或释放床位');
    } catch (e: any) {
      console.error(e);
      setAvailableBeds([]);
      setAvailableLockers([]);
      message.error(e?.message || '宿舍床位和柜子加载失败');
    } finally {
      setAvailableResourcesLoading(false);
    }
  };

  const handleTransferRoomChange = async (roomId: number) => {
    transferForm.setFieldValue('newBedId', undefined);
    transferForm.setFieldValue('newLockerId', undefined);
    setTransferAvailableBeds([]);
    setTransferAvailableLockers([]);
    if (!roomId) return;

    setTransferResourcesLoading(true);
    try {
      const [beds, lockers] = await Promise.all([
        api.get<any[]>(`/rooms/${roomId}/beds/available`),
        api.get<any[]>(`/rooms/${roomId}/lockers/available`),
      ]);
      setTransferAvailableBeds(beds);
      setTransferAvailableLockers(lockers);
      if (beds.length === 1) transferForm.setFieldValue('newBedId', beds[0].id);
      if (beds.length === 0) message.warning('目标宿舍暂无可用床位，请先在宿舍详情添加或释放床位');
    } catch (e: any) {
      console.error(e);
      setTransferAvailableBeds([]);
      setTransferAvailableLockers([]);
      message.error(e?.message || '目标宿舍床位和柜子加载失败');
    } finally {
      setTransferResourcesLoading(false);
    }
  };

  const filteredData = useMemo(() => {
    if (!searchText) return data;
    const keyword = searchText.toLowerCase();
    return data.filter(
      (r: any) =>
        r.student?.name?.toLowerCase().includes(keyword) ||
        r.room?.roomNumber?.toLowerCase().includes(keyword),
    );
  }, [data, searchText]);

  const handleCheckIn = async () => {
    const values = await checkInForm.validateFields();
    setSaving(true);
    try {
      await api.post('/occupancies/check-in', buildCheckInPayload(values));
      message.success('入住登记成功');
      setCheckInModal(false);
      checkInForm.resetFields();
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '操作失败');
    } finally {
      setSaving(false);
    }
  };

  const handleCheckOut = async () => {
    const values = await checkOutForm.validateFields();
    setSaving(true);
    try {
      await api.put(`/occupancies/${checkOutModal.id}/check-out`, {
        checkOutDate: values.checkOutDate.format('YYYY-MM-DD'),
        billingEndDate: values.billingEndDate?.format('YYYY-MM-DD'),
        checkOutReason: values.checkOutReason,
      });
      message.success('退宿成功');
      setCheckOutModal(null);
      checkOutForm.resetFields();
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '操作失败');
    } finally {
      setSaving(false);
    }
  };

  const handleTransfer = async () => {
    const values = await transferForm.validateFields();
    setSaving(true);
    try {
      await api.put(`/occupancies/${transferModal.id}/transfer`, buildTransferPayload(values));
      message.success('换房成功');
      setTransferModal(null);
      transferForm.resetFields();
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '操作失败');
    } finally {
      setSaving(false);
    }
  };

  const handleBatchCheckOut = async () => {
    const values = await batchCheckOutForm.validateFields();
    setBatchLoading(true);
    try {
      const res: any = await api.post('/occupancies/batch-check-out', {
        ids: selectedRowKeys,
        checkOutDate: values.checkOutDate.format('YYYY-MM-DD'),
        billingEndDate: values.billingEndDate?.format('YYYY-MM-DD'),
        checkOutReason: values.checkOutReason,
      });
      message.success(res.message || `已成功退宿 ${res.success} 人`);
      setBatchCheckOutModal(false);
      batchCheckOutForm.resetFields();
      setSelectedRowKeys([]);
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '批量退宿失败');
    } finally {
      setBatchLoading(false);
    }
  };

  const handleBatchDelete = async () => {
    setBatchLoading(true);
    try {
      const res: any = await api.post('/occupancies/batch-delete', { ids: selectedRowKeys });
      message.success(res?.message || `已归档 ${selectedRowKeys.length} 条`);
      setSelectedRowKeys([]);
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '批量归档失败');
    } finally {
      setBatchLoading(false);
    }
  };

  const columns = useMemo(
    () => [
      { title: '学生', width: 120, render: (_: any, r: any) => r.student?.name || '-' },
      { title: '宿舍', width: 120, render: (_: any, r: any) => r.room?.roomNumber || '-' },
      {
        title: '床位',
        width: 80,
        render: (_: unknown, r: Record<string, unknown>) =>
          (r.bed as Record<string, string> | undefined)?.bedNumber || '-',
      },
      {
        title: '柜子',
        width: 80,
        render: (_: unknown, r: Record<string, unknown>) =>
          (r.locker as Record<string, string> | undefined)?.lockerNumber || '-',
      },
      { title: '入住日期', dataIndex: 'checkInDate', width: 110 },
      { title: '计费起始', dataIndex: 'billingStartDate', width: 110 },
      {
        title: '退宿日期',
        dataIndex: 'checkOutDate',
        width: 110,
        render: (v: any) => v || <Tag color="green">在住</Tag>,
      },
      { title: '计费截止', dataIndex: 'billingEndDate', render: (v: any) => v || '-' },
      { title: '退宿原因', dataIndex: 'checkOutReason', render: (v: any) => v || '-' },
      {
        title: '操作',
        width: 220,
        render: (_: any, record: any) =>
          !record.checkOutDate ? (
            <Space>
              <PermissionButton
                permission="occupancy:checkout"
                size="small"
                icon={<LogoutOutlined />}
                onClick={() => {
                  setCheckOutModal(record);
                  checkOutForm.setFieldsValue({ checkOutDate: dayjs() });
                }}
              >
                退宿
              </PermissionButton>
              <PermissionButton
                permission="occupancy:transfer"
                size="small"
                icon={<SwapOutlined />}
                onClick={() => {
                  setTransferAvailableBeds([]);
                  setTransferAvailableLockers([]);
                  transferForm.resetFields();
                  setTransferModal(record);
                  transferForm.setFieldsValue({ transferDate: dayjs() });
                }}
              >
                换房
              </PermissionButton>
            </Space>
          ) : (
            <Space>
              <Tag>已退宿</Tag>
              <Popconfirm
                title="确定归档此记录？"
                onConfirm={async () => {
                  try {
                    await api.delete(`/occupancies/${record.id}`);
                    message.success('归档成功');
                    fetchData();
                  } catch (e: any) {
                    message.error(e?.message || '归档失败');
                  }
                }}
              >
                <PermissionButton
                  permission="occupancy:delete"
                  size="small"
                  danger
                  icon={<InboxOutlined />}
                >
                  归档
                </PermissionButton>
              </Popconfirm>
            </Space>
          ),
      },
    ],
    [fetchData, setCheckOutModal, checkOutForm, setTransferModal, transferForm],
  );

  const rowSelection = useMemo(
    () => ({
      selectedRowKeys,
      onChange: (keys: any[]) => setSelectedRowKeys(keys),
      // 「在住记录」Tab：禁用已退宿（防止误选用于批量退宿）；「全部记录」Tab：均可选用于批量归档
      getCheckboxProps: (record: any) => (showActive ? { disabled: !!record.checkOutDate } : {}),
    }),
    [selectedRowKeys, showActive],
  );

  return (
    <div>
      <Alert
        title="一站式导入"
        description="导入入住名单时会优先按手机号关联已有学生，所属机构自动取学生档案；未找到学生或宿舍时会自动创建。后续仅需在此页面处理换房/退宿等日常操作即可。"
        type="info"
        showIcon
        closable
        style={{ marginBottom: 16 }}
      />
      <div className="responsive-toolbar">
        <Space wrap className="responsive-toolbar__group">
          <Button type={showActive ? 'primary' : 'default'} onClick={() => setShowActive(true)}>
            在住记录
          </Button>
          <Button type={!showActive ? 'primary' : 'default'} onClick={() => setShowActive(false)}>
            全部记录
          </Button>
          <Input.Search
            placeholder="搜索学生姓名或房间号"
            onSearch={setSearchText}
            allowClear
            style={{ width: 200 }}
          />
          <RangePicker
            value={dateRange}
            onChange={(dates) => {
              setDateRange(dates ? [dates[0], dates[1]] : null);
            }}
            placeholder={['入住开始', '入住结束']}
            style={{ width: 240 }}
          />
        </Space>
        <Space wrap className="responsive-toolbar__group">
          <PermissionButton
            permission="occupancy:checkin"
            type="primary"
            icon={<PlusOutlined />}
            onClick={() => {
              checkInForm.resetFields();
              setAvailableBeds([]);
              setAvailableLockers([]);
              setAvailableResourcesLoading(false);
              const today = dayjs();
              checkInForm.setFieldsValue({
                checkInDate: today,
                billingStartDate: today,
                stayType: 'short',
                collectDeposit: true,
                depositAmount: 500,
              });
              setCheckInModal(true);
            }}
          >
            入住登记
          </PermissionButton>
          <Upload
            accept=".xlsx,.xls"
            showUploadList={false}
            customRequest={async ({ file, onSuccess, onError }: any) => {
              const formData = new FormData();
              formData.append('file', file);
              const params = new URLSearchParams();
              if (autoDeposit) {
                params.set('autoDeposit', 'true');
                params.set('depositAmount', String(depositAmount));
              }
              try {
                const res: any = await api.post(
                  `/occupancies/import?${params.toString()}`,
                  formData,
                  { headers: { 'Content-Type': 'multipart/form-data' } },
                );
                if (res.errors?.length > 0) {
                  Modal.warning({
                    title: res.message,
                    content: res.errors.join('\n'),
                    width: 500,
                  });
                } else {
                  message.success(res.message);
                }
                onSuccess?.(res);
                fetchData();
              } catch (e: any) {
                message.error(e?.message || '导入失败');
                onError?.(e);
              }
            }}
          >
            <Tooltip title="按手机号关联学生，并自动创建缺失的学生、宿舍和入住记录">
              <Button type="primary" ghost icon={<UploadOutlined />}>
                导入入住名单
              </Button>
            </Tooltip>
          </Upload>
          <PermissionButton
            permission="occupancy:view"
            icon={<DownloadOutlined />}
            onClick={() => {
              downloadBlob('/occupancies/template', '入住名单导入模板.xlsx').catch(() =>
                message.error('下载失败'),
              );
            }}
          >
            下载模板
          </PermissionButton>
          <PermissionButton
            permission="occupancy:view"
            icon={<ExportOutlined />}
            onClick={() => {
              const params = showActive ? '?active=true' : '';
              const filename = showActive ? '在住记录.xlsx' : '全部入住记录.xlsx';
              downloadBlob('/occupancies/export' + params, filename).catch(() =>
                message.error('导出失败'),
              );
            }}
          >
            导出记录
          </PermissionButton>
          <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 13 }}>
            <Switch size="small" checked={autoDeposit} onChange={setAutoDeposit} />
            导入时自动收押金
            {autoDeposit && (
              <Space.Compact>
                <InputNumber
                  size="small"
                  min={0}
                  value={depositAmount}
                  onChange={(v) => setDepositAmount(v || 500)}
                  style={{ width: 60 }}
                />
                <span
                  style={{
                    padding: '0 8px',
                    display: 'flex',
                    alignItems: 'center',
                    border: '1px solid #d9d9d9',
                    backgroundColor: '#fafafa',
                    fontSize: 12,
                  }}
                >
                  元
                </span>
              </Space.Compact>
            )}
          </span>
        </Space>
      </div>
      {selectedRowKeys.length > 0 && (
        <Alert
          title={
            <span>
              已选 <strong>{selectedRowKeys.length}</strong> 条记录
              {showActive ? (
                <PermissionButton
                  permission="occupancy:checkout"
                  type="primary"
                  size="small"
                  icon={<LogoutOutlined />}
                  onClick={() => {
                    batchCheckOutForm.resetFields();
                    batchCheckOutForm.setFieldsValue({ checkOutDate: dayjs() });
                    setBatchCheckOutModal(true);
                  }}
                  style={{ marginLeft: 12 }}
                  loading={batchLoading}
                >
                  批量退宿
                </PermissionButton>
              ) : (
                <Popconfirm
                  title={`确定归档选中的 ${selectedRowKeys.length} 条入住记录？在住记录会自动跳过`}
                  onConfirm={handleBatchDelete}
                  okText="归档"
                  cancelText="取消"
                >
                  <PermissionButton
                    permission="occupancy:delete"
                    danger
                    size="small"
                    icon={<InboxOutlined />}
                    style={{ marginLeft: 12 }}
                    loading={batchLoading}
                  >
                    批量归档
                  </PermissionButton>
                </Popconfirm>
              )}
              <Button size="small" onClick={() => setSelectedRowKeys([])} style={{ marginLeft: 8 }}>
                取消选择
              </Button>
            </span>
          }
          type="info"
          style={{ marginBottom: 12 }}
        />
      )}
      <Table
        columns={columns}
        dataSource={filteredData}
        rowKey="id"
        loading={loading}
        locale={{ emptyText: <Empty description="暂无数据" /> }}
        scroll={{ x: 1300 }}
        pagination={{
          defaultPageSize: 15,
          showSizeChanger: true,
          pageSizeOptions: [15, 30, 50, 100],
          showTotal: (total) => `共 ${total} 条`,
        }}
        rowSelection={rowSelection}
      />
      <Modal
        title="入住登记"
        open={checkInModal}
        onOk={handleCheckIn}
        onCancel={() => {
          setCheckInModal(false);
          setAvailableBeds([]);
          setAvailableLockers([]);
          setAvailableResourcesLoading(false);
        }}
        okText="确认入住"
        confirmLoading={saving}
        width={500}
      >
        <Form form={checkInForm} layout="vertical">
          <Form.Item
            name="studentId"
            label="选择学生"
            rules={[{ required: true, message: '请选择学生' }]}
          >
            <Select
              showSearch
              optionFilterProp="label"
              placeholder="搜索并选择学生"
              options={students
                .filter((s: any) => s.status === 'active')
                .map((s: any) => {
                  const activeOccupancy = activeOccupancyByStudentId.get(s.id);
                  const identifier = s.idNumber ? maskIdNumber(s.idNumber) : s.phone ? maskPhone(s.phone) : '';
                  return {
                    value: s.id,
                    label: `${s.name} (${identifier})${activeOccupancy ? ` · 已入住${activeOccupancy.room?.roomNumber ? ` ${activeOccupancy.room.roomNumber}` : ''}` : ''}`,
                    disabled: !!activeOccupancy,
                  };
                })}
            />
          </Form.Item>
          <Form.Item
            name="roomId"
            label="选择宿舍"
            rules={[{ required: true, message: '请选择宿舍' }]}
          >
            <Select
              showSearch
              optionFilterProp="label"
              placeholder="搜索并选择宿舍"
              onChange={handleRoomChange}
              options={rooms.map((r) => ({
                value: r.id,
                label: roomOptionLabel(r),
                disabled: !isRoomSelectable(r),
              }))}
            />
          </Form.Item>
          <Form.Item name="checkInDate" label="入住日期" rules={[{ required: true, message: '请选择入住日期' }]}>
            <DatePicker style={{ width: '100%' }} placeholder="选择入住日期" format="YYYY-MM-DD" />
          </Form.Item>
          <Form.Item
            name="billingStartDate"
            label="计费起始日"
            dependencies={["checkInDate"]}
            extra="默认与入住日期相同，可调整（如学生要求从次日开始计费）"
            rules={[
              { required: true, message: '请选择计费起始日' },
              ({ getFieldValue }) => ({
                validator: dateNotBefore(getFieldValue('checkInDate'), '计费起始日不能早于入住日期'),
              }),
            ]}
          >
            <DatePicker
              style={{ width: '100%' }}
              placeholder="选择计费起始日"
              format="YYYY-MM-DD"
            />
          </Form.Item>
          <Form.Item name="stayType" label="入住类型" rules={[{ required: true, message: '请选择入住类型' }]}>
            <Select
              options={[
                { value: 'short', label: '短租' },
                { value: 'long', label: '长租' },
              ]}
              placeholder="默认为短租"
            />
          </Form.Item>
          <Form.Item
            name="bedId"
            label="床位"
            rules={[
              { required: true, message: '请选择床位' },
              {
                validator: (_: unknown, value?: number) =>
                  !value || availableBeds.some((bed) => bed.id === value)
                    ? Promise.resolve()
                    : Promise.reject(new Error('请选择当前宿舍下的可用床位')),
              },
            ]}
          >
            <Select
              placeholder={selectedCheckInRoomId ? '请选择床位' : '请先选择房间'}
              loading={availableResourcesLoading}
              disabled={!selectedCheckInRoomId || availableResourcesLoading || availableBeds.length === 0}
              options={availableBeds.map((b) => ({
                value: b.id,
                label: b.bedNumber,
              }))}
              notFoundContent={selectedCheckInRoomId ? '该房间暂无可用床位' : '请先选择房间'}
            />
          </Form.Item>
          {availableBeds.length > 0 && (
            <div style={{ marginTop: -16, marginBottom: 16, color: '#888', fontSize: 12 }}>
              空闲 {availableBeds.length} 张床位
            </div>
          )}
          <Form.Item name="lockerId" label="柜子（可选）">
            <Select
              allowClear
              placeholder="可选分配柜子"
              loading={availableResourcesLoading}
              disabled={!selectedCheckInRoomId || availableResourcesLoading || availableLockers.length === 0}
              options={availableLockers.map((l) => ({
                value: l.id,
                label: l.lockerNumber,
              }))}
            />
          </Form.Item>
          <Form.Item
            name="collectDeposit"
            label="押金缴纳"
            valuePropName="checked"
            extra="开启后，确认入住时同步生成已缴押金记录；已有已缴押金时不会重复创建"
          >
            <Switch checkedChildren="已缴" unCheckedChildren="不缴" />
          </Form.Item>
          <Form.Item
            noStyle
            shouldUpdate={(prev, current) => prev.collectDeposit !== current.collectDeposit}
          >
            {({ getFieldValue }) =>
              getFieldValue('collectDeposit') ? (
                <Form.Item
                  name="depositAmount"
                  label="押金金额"
                  rules={[{ required: true, message: '请输入押金金额' }]}
                >
                  <InputNumber min={0.01} precision={2} addonAfter="元" style={{ width: '100%' }} />
                </Form.Item>
              ) : null
            }
          </Form.Item>
          <Form.Item name="notes" label="备注">
            <Input.TextArea rows={2} />
          </Form.Item>
        </Form>
      </Modal>

      {/* 退宿弹窗 */}
      <Modal
        title={`退宿 - ${checkOutModal?.student?.name}`}
        open={!!checkOutModal}
        onOk={handleCheckOut}
        onCancel={() => setCheckOutModal(null)}
        okText="确认退宿"
        confirmLoading={saving}
      >
        <Form form={checkOutForm} layout="vertical">
          <Form.Item
            name="checkOutDate"
            label="退宿日期"
            rules={[
              { required: true, message: '请选择退宿日期' },
              { validator: dateNotBefore(checkOutModal?.checkInDate, '退宿日期不能早于入住日期') },
            ]}
          >
            <DatePicker style={{ width: '100%' }} placeholder="选择退宿日期" format="YYYY-MM-DD" />
          </Form.Item>
          <Form.Item
            name="billingEndDate"
            label="计费截止日"
            dependencies={["checkOutDate"]}
            extra="默认与退宿日期相同"
            rules={[
              ({ getFieldValue }) => ({
                validator: dateNotBefore(
                  checkOutModal?.billingStartDate || checkOutModal?.checkInDate || getFieldValue('checkOutDate'),
                  '计费截止日不能早于计费起始日',
                ),
              }),
            ]}
          >
            <DatePicker
              style={{ width: '100%' }}
              placeholder="选择计费截止日"
              format="YYYY-MM-DD"
            />
          </Form.Item>
          <Form.Item name="checkOutReason" label="退宿原因">
            <Select
              allowClear
              options={[
                { value: '换房', label: '换房' },
                { value: '退训', label: '退训' },
                { value: '结业', label: '结业' },
                { value: '毕业', label: '毕业' },
                { value: '其他', label: '其他' },
              ]}
            />
          </Form.Item>
        </Form>
      </Modal>

      {/* 批量退宿弹窗 */}
      <Modal
        title={`批量退宿（${selectedRowKeys.length} 人）`}
        open={batchCheckOutModal}
        onOk={handleBatchCheckOut}
        onCancel={() => setBatchCheckOutModal(false)}
        okText="确认批量退宿"
        width={500}
      >
        <Form form={batchCheckOutForm} layout="vertical">
          <Form.Item
            name="checkOutDate"
            label="退宿日期"
            rules={[
              { required: true, message: '请选择退宿日期' },
              {
                validator: dateNotBefore(
                  latestSelectedCheckInDate,
                  '退宿日期不能早于所选记录中最晚的入住日期',
                ),
              },
            ]}
          >
            <DatePicker style={{ width: '100%' }} placeholder="选择退宿日期" format="YYYY-MM-DD" />
          </Form.Item>
          <Form.Item
            name="billingEndDate"
            label="计费截止日"
            extra="默认与退宿日期相同"
            rules={[
              {
                validator: dateNotBefore(
                  latestSelectedBillingStartDate,
                  '计费截止日不能早于所选记录中最晚的计费起始日',
                ),
              },
            ]}
          >
            <DatePicker
              style={{ width: '100%' }}
              placeholder="选择计费截止日"
              format="YYYY-MM-DD"
            />
          </Form.Item>
          <Form.Item name="checkOutReason" label="退宿原因">
            <Select
              allowClear
              options={[
                { value: '结业', label: '结业' },
                { value: '退训', label: '退训' },
                { value: '毕业', label: '毕业' },
                { value: '其他', label: '其他' },
              ]}
            />
          </Form.Item>
        </Form>
        <div
          style={{
            marginTop: 12,
            padding: '8px 12px',
            background: '#f5f5f5',
            borderRadius: 6,
            maxHeight: 150,
            overflow: 'auto',
          }}
        >
          <div style={{ fontSize: 12, color: '#666', marginBottom: 4 }}>即将退宿的学生：</div>
          {data
            .filter((r: any) => selectedRowKeys.includes(r.id))
            .map((r: any) => (
              <Tag key={r.id} style={{ marginBottom: 4 }}>
                {r.student?.name} ({r.room?.roomNumber})
              </Tag>
            ))}
        </div>
      </Modal>

      {/* 换房弹窗 */}
      <Modal
        title={`换房 - ${transferModal?.student?.name}`}
        open={!!transferModal}
        onOk={handleTransfer}
        onCancel={() => {
          setTransferModal(null);
          transferForm.resetFields();
          setTransferAvailableBeds([]);
          setTransferAvailableLockers([]);
        }}
        okText="确认换房"
        confirmLoading={saving}
        width={500}
      >
        <Form form={transferForm} layout="vertical">
          <Form.Item name="newRoomId" label="目标宿舍" rules={[{ required: true }]}>
            <Select
              showSearch
              optionFilterProp="label"
              placeholder="选择目标宿舍"
              onChange={handleTransferRoomChange}
              options={rooms
                .filter((r: any) => r.id !== transferModal?.roomId)
                .map((r: any) => ({
                  value: r.id,
                  label: roomOptionLabel(r),
                  disabled: !isRoomSelectable(r),
                }))}
            />
          </Form.Item>
          <Form.Item
            name="newBedId"
            label="目标床位"
            rules={[
              { required: true, message: '请选择目标床位' },
              {
                validator: (_: unknown, value?: number) =>
                  !value || transferAvailableBeds.some((bed) => bed.id === value)
                    ? Promise.resolve()
                    : Promise.reject(new Error('请选择目标宿舍下的可用床位')),
              },
            ]}
          >
            <Select
              placeholder={selectedTransferRoomId ? '请选择目标床位' : '请先选择目标宿舍'}
              loading={transferResourcesLoading}
              disabled={!selectedTransferRoomId || transferResourcesLoading || transferAvailableBeds.length === 0}
              options={transferAvailableBeds.map((bed) => ({
                value: bed.id,
                label: bed.bedNumber,
              }))}
              notFoundContent={selectedTransferRoomId ? '目标宿舍暂无可用床位' : '请先选择目标宿舍'}
            />
          </Form.Item>
          {transferAvailableBeds.length > 0 && (
            <div style={{ marginTop: -16, marginBottom: 16, color: '#888', fontSize: 12 }}>
              空闲 {transferAvailableBeds.length} 张床位
            </div>
          )}
          <Form.Item name="newLockerId" label="目标柜子（可选）">
            <Select
              allowClear
              placeholder="可选分配目标宿舍柜子"
              loading={transferResourcesLoading}
              disabled={!selectedTransferRoomId || transferResourcesLoading || transferAvailableLockers.length === 0}
              options={transferAvailableLockers.map((locker) => ({
                value: locker.id,
                label: locker.lockerNumber,
              }))}
              notFoundContent="目标宿舍暂无可用柜子"
            />
          </Form.Item>
          <Form.Item
            name="transferDate"
            label="换房日期"
            rules={[
              { required: true, message: '请选择换房日期' },
              { validator: dateNotBefore(transferModal?.checkInDate, '换房日期不能早于原入住日期') },
            ]}
          >
            <DatePicker style={{ width: '100%' }} placeholder="选择换房日期" format="YYYY-MM-DD" />
          </Form.Item>
          <Form.Item
            name="oldBillingEndDate"
            label="旧房计费截止日"
            dependencies={["transferDate"]}
            extra="默认为换房当天"
            rules={[
              ({ getFieldValue }) => ({
                validator: dateNotBefore(
                  transferModal?.billingStartDate || transferModal?.checkInDate || getFieldValue('transferDate'),
                  '旧房计费截止日不能早于计费起始日',
                ),
              }),
            ]}
          >
            <DatePicker
              style={{ width: '100%' }}
              placeholder="选择旧房计费截止日"
              format="YYYY-MM-DD"
            />
          </Form.Item>
          <Form.Item
            name="newBillingStartDate"
            label="新房计费起始日"
            dependencies={["transferDate"]}
            extra="默认为换房次日"
            rules={[
              ({ getFieldValue }) => ({
                validator: dateNotBefore(getFieldValue('transferDate'), '新房计费起始日不能早于换房日期'),
              }),
            ]}
          >
            <DatePicker
              style={{ width: '100%' }}
              placeholder="选择新房计费起始日"
              format="YYYY-MM-DD"
            />
          </Form.Item>
          <Form.Item name="reason" label="换房原因">
            <Input />
          </Form.Item>
        </Form>
      </Modal>
    </div>
  );
};

export default OccupanciesPage;
