import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
  Table,
  Button,
  Modal,
  Form,
  Select,
  DatePicker,
  InputNumber,
  Input,
  Space,
  Tag,
  Popconfirm,
  Upload,
  Tooltip,
  Empty,
} from 'antd';
import {
  PlusOutlined,
  UploadOutlined,
  FileTextOutlined,
  StopOutlined,
  CheckOutlined,
} from '@ant-design/icons';
import dayjs, { Dayjs } from 'dayjs';
import api from '../../api';
import { downloadBlob } from '../../utils/download';
import PermissionButton from '../../components/PermissionButton';
import EditableCell from '../../components/EditableCell';
import { message } from '../../ui/app-message';
import { usePermission } from '../../hooks/usePermission';

interface UnavailableDatesResponse {
  dates: string[];
}
export const unavailableDatesCacheKey = (classroomId: number, date: Dayjs) =>
  `${classroomId}:${date.format('YYYY-MM')}`;

const ClassroomRentalsPage: React.FC = () => {
  const { hasPermission, hasAnyPermission } = usePermission();
  const [data, setData] = useState<any[]>([]);
  const [classrooms, setClassrooms] = useState<any[]>([]);
  const [organizations, setOrganizations] = useState<any[]>([]);
  const [loading, setLoading] = useState(false);
  const [modalOpen, setModalOpen] = useState(false);
  const [editing, setEditing] = useState<any>(null);
  const [form] = Form.useForm();
  const [filterMonth, setFilterMonth] = useState<Dayjs | null>(null);
  const [filterStatus, setFilterStatus] = useState<string | undefined>();
  const [searchText, setSearchText] = useState('');
  const [saving, setSaving] = useState(false);
  const [unavailableDates, setUnavailableDates] = useState<Set<string>>(new Set());
  const loadedUnavailableMonths = useRef<Set<string>>(new Set());
  const unavailableRequestVersion = useRef(0);
  const [unavailableDatesLoading, setUnavailableDatesLoading] = useState(false);
  const selectedClassroomId = Form.useWatch('classroomId', form);

  const filteredData = useMemo(() => {
    return data.filter((r: any) => {
      if (filterStatus && r.effectiveStatus !== filterStatus) return false;
      if (!searchText) return true;
      const s = searchText.toLowerCase();
      const matchClassroom = r.classroom?.name?.toLowerCase().includes(s);
      const matchOrganization = r.lesseeOrganization?.name?.toLowerCase().includes(s);
      return matchClassroom || matchOrganization;
    });
  }, [data, searchText, filterStatus]);

  const fetchData = async () => {
    setLoading(true);
    try {
      const params: any = {};
      if (filterMonth) params.month = filterMonth.format('YYYY-MM');
      params.includeEnded = true;
      const res: any = await api.get('/classroom-rentals', { params });
      setData(res);
    } catch (e: any) {
      message.error(e?.message || '加载失败，请稍后重试');
    }
    setLoading(false);
  };

  const fetchMeta = async () => {
    try {
      const [cr, tn]: any = await Promise.all([
        api.get('/classrooms'),
        api.get('/organizations', { params: { scope: 'all' } }),
      ]);
      setClassrooms(cr);
      setOrganizations(tn);
    } catch (e: any) {
      message.error(e?.message || '加载教室列表失败');
    }
  };

  useEffect(() => {
    if (hasAnyPermission('rental:create', 'rental:edit')) fetchMeta();
  }, [hasAnyPermission]);
  useEffect(() => {
    fetchData();
  }, [filterMonth]);

  const resetUnavailableDates = () => {
    unavailableRequestVersion.current += 1;
    loadedUnavailableMonths.current.clear();
    setUnavailableDates(new Set());
  };

  const loadUnavailableDates = useCallback(
    async (classroomId: number, date: Dayjs, excludeId?: number) => {
      const key = unavailableDatesCacheKey(classroomId, date);
      if (loadedUnavailableMonths.current.has(key)) return;
      loadedUnavailableMonths.current.add(key);
      const requestVersion = unavailableRequestVersion.current;

      setUnavailableDatesLoading(true);
      try {
        const response = await api.get<UnavailableDatesResponse>(
          '/classroom-rentals/unavailable-dates',
          {
            params: {
              classroomId,
              year: date.year(),
              month: date.month() + 1,
              excludeId,
            },
          },
        );
        if (requestVersion !== unavailableRequestVersion.current) return;
        setUnavailableDates((current) => {
          const next = new Set(current);
          response.dates.forEach((item) => next.add(item));
          return next;
        });
      } catch (e: any) {
        loadedUnavailableMonths.current.delete(key);
        if (requestVersion === unavailableRequestVersion.current) {
          message.error(e?.message || '加载教室占用日期失败');
        }
      } finally {
        if (requestVersion === unavailableRequestVersion.current) {
          setUnavailableDatesLoading(false);
        }
      }
    },
    [],
  );

  const handleClassroomChange = (classroomId: number) => {
    form.setFieldValue('dateRange', undefined);
    resetUnavailableDates();
    void loadUnavailableDates(classroomId, dayjs(), editing?.id);
    void loadUnavailableDates(classroomId, dayjs().add(1, 'month'), editing?.id);
  };

  const handleCalendarChange = (date: Dayjs) => {
    const classroomId = form.getFieldValue('classroomId');
    if (classroomId) void loadUnavailableDates(classroomId, date, editing?.id);
  };

  const isDateUnavailable = (date: Dayjs) => unavailableDates.has(date.format('YYYY-MM-DD'));

  const rangeIncludesUnavailableDate = (range?: [Dayjs, Dayjs]) => {
    if (!range) return false;
    for (
      let date = range[0].startOf('day');
      !date.isAfter(range[1], 'day');
      date = date.add(1, 'day')
    ) {
      if (isDateUnavailable(date)) return true;
    }
    return false;
  };

  const handleSave = async () => {
    const values = await form.validateFields();
    if (rangeIncludesUnavailableDate(values.dateRange)) {
      message.error('所选日期范围包含已排课或已租赁日期，请重新选择');
      return;
    }
    setSaving(true);
    const payload = {
      classroomId: values.classroomId,
      lessorOrganizationId: values.lessorOrganizationId,
      lesseeOrganizationId: values.lesseeOrganizationId,
      startDate: values.dateRange[0].format('YYYY-MM-DD'),
      endDate: values.dateRange[1].format('YYYY-MM-DD'),
      dailyRate: values.dailyRate,
      totalAmount: values.totalAmount,
      notes: values.notes,
    };
    try {
      if (editing) {
        await api.put(`/classroom-rentals/${editing.id}`, payload);
        message.success('更新成功');
      } else {
        await api.post('/classroom-rentals', payload);
        message.success('创建成功');
      }
      setModalOpen(false);
      form.resetFields();
      setEditing(null);
      fetchData();
    } catch (e: any) {
      if (e?.conflicts?.length) {
        const list = e.conflicts
          .map((c: any) => `${c.organizationName}(${c.startDate}~${c.endDate})`)
          .join('、');
        message.error(`时间段冲突：${list}`);
      } else {
        message.error(e?.message || '操作失败');
      }
    } finally {
      setSaving(false);
    }
  };

  const saveCell = async (record: any, field: string, value: unknown) => {
    await api.put(`/classroom-rentals/${record.id}`, { [field]: value });
    message.success('已保存');
    await fetchData();
  };

  const handleDelete = async (id: number) => {
    try {
      await api.delete(`/classroom-rentals/${id}`);
      message.success('已归档');
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '归档失败');
    }
  };

  const handleRentalAction = async (id: number, action: 'cancel' | 'end') => {
    try {
      await api.put(`/classroom-rentals/${id}/${action}`);
      message.success(action === 'cancel' ? '租赁已取消' : '租赁已结束');
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '操作失败');
    }
  };

  const handleDownloadContract = async (id: number, filename?: string) => {
    try {
      await downloadBlob(`/classroom-rentals/${id}/contract`, filename || `contract-${id}.pdf`);
    } catch {
      message.error('下载失败（可能文件已丢失）');
    }
  };

  const handleDeleteContract = async (id: number) => {
    try {
      await api.delete(`/classroom-rentals/${id}/contract`);
      message.success('合同已移除');
      fetchData();
    } catch (e: any) {
      message.error(e?.message || '移除失败');
    }
  };

  const openEdit = (record: any) => {
    setEditing(record);
    resetUnavailableDates();
    form.setFieldsValue({
      classroomId: record.classroomId,
      lessorOrganizationId: record.lessorOrganizationId,
      lesseeOrganizationId: record.lesseeOrganizationId,
      dateRange: [dayjs(record.startDate), dayjs(record.endDate)],
      dailyRate: record.dailyRate ? Number(record.dailyRate) : undefined,
      totalAmount: record.totalAmount ? Number(record.totalAmount) : undefined,
      notes: record.notes,
    });
    setModalOpen(true);
    void loadUnavailableDates(record.classroomId, dayjs(record.startDate), record.id);
    void loadUnavailableDates(
      record.classroomId,
      dayjs(record.startDate).add(1, 'month'),
      record.id,
    );
  };

  const columns = useMemo(
    () => [
      {
        title: '教室',
        width: 120,
        dataIndex: 'classroom',
        render: (c: any, r: any) => (
          <EditableCell
            value={r.classroomId}
            editor="select"
            options={classrooms
              .filter((item) => item.status !== 'archived')
              .map((item) => ({
                value: item.id,
                label: item.building ? `${item.building} · ${item.name}` : item.name,
              }))}
            permission="rental:edit"
            disabled={r.effectiveStatus !== 'active'}
            required
            onSave={(next) => saveCell(r, 'classroomId', next)}
          >
            {c ? (
              <span>
                {c.building ? `${c.building} · ` : ''}
                {c.name}
              </span>
            ) : (
              '-'
            )}
          </EditableCell>
        ),
      },
      {
        title: '承租机构',
        width: 100,
        dataIndex: 'lesseeOrganization',
        render: (t: any, r: any) => (
          <EditableCell
            value={r.lesseeOrganizationId}
            editor="select"
            options={organizations
              .filter((item) => item.status !== 'archived')
              .map((item) => ({ value: item.id, label: item.name }))}
            permission="rental:edit"
            disabled={r.effectiveStatus !== 'active'}
            required
            onSave={(next) => saveCell(r, 'lesseeOrganizationId', next)}
          >
            {t ? (
              <Tag
                color={t.color}
                style={{ background: t.color, color: '#fff', borderColor: t.color }}
              >
                {t.name}
              </Tag>
            ) : (
              '-'
            )}
          </EditableCell>
        ),
      },
      {
        title: '开始日期',
        dataIndex: 'startDate',
        width: 110,
        render: (v: string, r: any) => (
          <EditableCell
            value={v}
            editor="date"
            permission="rental:edit"
            disabled={r.effectiveStatus !== 'active'}
            required
            onSave={(next) => saveCell(r, 'startDate', next)}
          >
            {v}
          </EditableCell>
        ),
      },
      {
        title: '结束日期',
        dataIndex: 'endDate',
        width: 110,
        render: (v: string, r: any) => (
          <EditableCell
            value={v}
            editor="date"
            permission="rental:edit"
            disabled={r.effectiveStatus !== 'active'}
            required
            onSave={(next) => saveCell(r, 'endDate', next)}
          >
            {v}
          </EditableCell>
        ),
      },
      {
        title: '时长',
        width: 80,
        render: (_: any, r: any) => {
          const d = dayjs(r.endDate).diff(dayjs(r.startDate), 'day') + 1;
          return `${d}天`;
        },
      },
      {
        title: '日租金',
        dataIndex: 'dailyRate',
        width: 100,
        render: (v: any, r: any) => (
          <EditableCell
            value={v}
            editor="money"
            min={0.01}
            permission="rental:edit"
            disabled={r.effectiveStatus !== 'active'}
            onSave={(next) => saveCell(r, 'dailyRate', next)}
          >
            {v ? `¥${v}` : '-'}
          </EditableCell>
        ),
      },
      {
        title: '总额',
        dataIndex: 'totalAmount',
        width: 100,
        render: (v: any, r: any) => (
          <EditableCell
            value={v}
            editor="money"
            min={0.01}
            permission="rental:edit"
            disabled={r.effectiveStatus !== 'active'}
            onSave={(next) => saveCell(r, 'totalAmount', next)}
          >
            {v ? `¥${v}` : '-'}
          </EditableCell>
        ),
      },
      {
        title: '状态',
        dataIndex: 'effectiveStatus',
        width: 90,
        render: (status: string) => {
          const config: Record<string, { text: string; color: string }> = {
            active: { text: '进行中', color: 'green' },
            ended: { text: '已结束', color: 'default' },
            cancelled: { text: '已取消', color: 'red' },
          };
          return <Tag color={config[status]?.color}>{config[status]?.text || status}</Tag>;
        },
      },
      {
        title: '合同',
        width: 120,
        dataIndex: 'contractPath',
        render: (v: string, r: any) =>
          v ? (
            <Space>
              <Tooltip title={r.contractOriginalName}>
                <Button
                  size="small"
                  icon={<FileTextOutlined />}
                  onClick={() => handleDownloadContract(r.id, r.contractOriginalName)}
                >
                  下载
                </Button>
              </Tooltip>
              {hasPermission('rental:edit') ? (
                <Popconfirm title="移除合同文件？" onConfirm={() => handleDeleteContract(r.id)}>
                  <Button size="small" danger icon={<StopOutlined />} aria-label="移除合同文件" />
                </Popconfirm>
              ) : null}
            </Space>
          ) : hasPermission('rental:edit') ? (
            <Upload
              accept="application/pdf"
              showUploadList={false}
              customRequest={async ({ file, onSuccess, onError }: any) => {
                if (file.size > 10 * 1024 * 1024) {
                  message.error('文件不能超过 10MB');
                  onError?.(new Error('size'));
                  return;
                }
                const formData = new FormData();
                formData.append('file', file);
                try {
                  await api.post(`/classroom-rentals/${r.id}/contract`, formData, {
                    headers: { 'Content-Type': 'multipart/form-data' },
                  });
                  message.success('合同已上传');
                  onSuccess?.({});
                  fetchData();
                } catch (e: any) {
                  message.error(e?.message || '上传失败');
                  onError?.(e);
                }
              }}
            >
              <Button size="small" icon={<UploadOutlined />}>
                上传PDF
              </Button>
            </Upload>
          ) : (
            '-'
          ),
      },
      {
        title: '操作',
        width: 150,
        render: (_: any, record: any) => (
          <Space>
            {record.effectiveStatus === 'active' && (
              <>
                <PermissionButton
                  permission="rental:edit"
                  size="small"
                  onClick={() => openEdit(record)}
                >
                  编辑
                </PermissionButton>
                <Popconfirm
                  title="确定取消该租赁？"
                  onConfirm={() => handleRentalAction(record.id, 'cancel')}
                >
                  <PermissionButton
                    permission="rental:edit"
                    size="small"
                    danger
                    icon={<StopOutlined />}
                  >
                    取消
                  </PermissionButton>
                </Popconfirm>
                {!dayjs(record.startDate).isAfter(dayjs(), 'day') && (
                  <Popconfirm
                    title="确定今天结束该租赁？"
                    onConfirm={() => handleRentalAction(record.id, 'end')}
                  >
                    <PermissionButton
                      permission="rental:edit"
                      size="small"
                      icon={<CheckOutlined />}
                    >
                      结束
                    </PermissionButton>
                  </Popconfirm>
                )}
              </>
            )}
            {record.effectiveStatus !== 'active' && (
              <Popconfirm
                title="确定归档该租赁订单？合同文件会保留。"
                onConfirm={() => handleDelete(record.id)}
              >
                <PermissionButton permission="rental:delete" size="small" danger>
                  归档
                </PermissionButton>
              </Popconfirm>
            )}
          </Space>
        ),
      },
    ],
    [classrooms, organizations, hasPermission],
  );

  return (
    <div>
      <div
        style={{
          marginBottom: 16,
          display: 'flex',
          justifyContent: 'space-between',
          flexWrap: 'wrap',
          gap: 8,
        }}
      >
        <Space wrap>
          <Input.Search
            placeholder="搜索教室/承租机构"
            allowClear
            style={{ width: 180 }}
            onSearch={(v) => setSearchText(v)}
            onChange={(e) => {
              if (!e.target.value) setSearchText('');
            }}
          />
          <DatePicker
            picker="month"
            placeholder="按月筛选"
            value={filterMonth}
            onChange={setFilterMonth}
            allowClear
            format="YYYY-MM"
          />
          <Select
            placeholder="状态"
            allowClear
            style={{ width: 110 }}
            value={filterStatus}
            onChange={setFilterStatus}
            options={[
              { value: 'active', label: '进行中' },
              { value: 'ended', label: '已结束' },
              { value: 'cancelled', label: '已取消' },
            ]}
          />
        </Space>
        <PermissionButton
          permission="rental:create"
          type="primary"
          icon={<PlusOutlined />}
          onClick={() => {
            setEditing(null);
            form.resetFields();
            resetUnavailableDates();
            setModalOpen(true);
          }}
        >
          新增租赁
        </PermissionButton>
      </div>
      <Table
        columns={columns}
        dataSource={filteredData}
        rowKey="id"
        loading={loading}
        locale={{ emptyText: <Empty description="暂无数据" /> }}
        pagination={{
          defaultPageSize: 15,
          showSizeChanger: true,
          pageSizeOptions: [15, 30, 50, 100],
          showTotal: (total) => `共 ${total} 条`,
        }}
        scroll={{ x: 1200 }}
      />
      <Modal
        title={editing ? '编辑租赁' : '新增租赁'}
        open={modalOpen}
        onOk={handleSave}
        onCancel={() => {
          setModalOpen(false);
          setEditing(null);
          resetUnavailableDates();
        }}
        confirmLoading={saving}
        okText="保存"
        width={600}
      >
        <Form form={form} layout="vertical">
          <Form.Item name="classroomId" label="教室" rules={[{ required: true }]}>
            <Select
              showSearch
              optionFilterProp="label"
              placeholder="选择教室"
              onChange={handleClassroomChange}
              options={classrooms
                .filter((c) => c.status === 'available')
                .map((c) => ({
                  value: c.id,
                  label: `${c.building ? c.building + ' · ' : ''}${c.name}（${c.roomType}）`,
                }))}
            />
          </Form.Item>
          <Form.Item name="lessorOrganizationId" label="出租机构" tooltip="默认由本机构出租">
            <Select
              showSearch
              optionFilterProp="label"
              placeholder="默认本机构"
              allowClear
              options={organizations
                .filter((organization) => organization.isHost)
                .map((organization) => ({
                  value: organization.id,
                  label: `${organization.name}（本机构）`,
                }))}
            />
          </Form.Item>
          <Form.Item
            name="lesseeOrganizationId"
            label="承租机构"
            rules={[{ required: true, message: '请选择承租机构' }]}
          >
            <Select
              showSearch
              optionFilterProp="label"
              placeholder="选择外部承租机构"
              options={organizations
                .filter((organization) => !organization.isHost && organization.status === 'active')
                .map((organization) => ({
                  value: organization.id,
                  label: organization.name,
                }))}
            />
          </Form.Item>
          <Form.Item name="dateRange" label="租赁起止日期" rules={[{ required: true }]}>
            <DatePicker.RangePicker
              style={{ width: '100%' }}
              placeholder={['开始日期', '结束日期']}
              format="YYYY-MM-DD"
              disabled={!selectedClassroomId}
              disabledDate={(date) => unavailableDatesLoading || isDateUnavailable(date)}
              onPanelChange={(dates) => dates.forEach((date) => date && handleCalendarChange(date))}
            />
          </Form.Item>
          <Form.Item name="dailyRate" label="日租金（可选）">
            <InputNumber min={0.01} precision={2} style={{ width: '100%' }} prefix="¥" />
          </Form.Item>
          <Form.Item name="totalAmount" label="合同总额（可选）">
            <InputNumber min={0.01} precision={2} style={{ width: '100%' }} prefix="¥" />
          </Form.Item>
          <Form.Item name="notes" label="备注">
            <Input.TextArea rows={2} />
          </Form.Item>
        </Form>
      </Modal>
    </div>
  );
};

export default ClassroomRentalsPage;
