import React, { useEffect, useState, useMemo, useCallback } from 'react';
import {
  Card,
  Button,
  Select,
  Modal,
  Form,
  Input,
  DatePicker,
  TimePicker,
  Popconfirm,
  Space,
  Spin,
  Empty,
  Tag,
  Tooltip,
  Segmented,
  Badge,
  Row,
  Col,
  Statistic,
  Alert,
  Switch,
} from 'antd';
import {
  CalendarOutlined,
  LeftOutlined,
  RightOutlined,
  DeleteOutlined,
  CloudSyncOutlined,
  PlusOutlined,
  EditOutlined,
} from '@ant-design/icons';
import dayjs, { Dayjs } from 'dayjs';
import api from '../../api';
import PermissionButton from '../../components/PermissionButton';
import { usePermission } from '../../hooks/usePermission';
import { message } from '../../ui/app-message';
import {
  buildSchedulePayload,
  scheduleToFormValues,
  type ScheduleFormValues,
} from './schedule-form';
import { filterSchedulesForClass, isMaskedSchedule } from './schedule-visibility';
import { classifySyncResult } from './sync-result';

// ---- Types ----

interface ClassScheduleItem {
  id: number | null;
  classId: number | null;
  classroomId: number;
  weekDay: number;
  startTime: string;
  endTime: string;
  startDate: string;
  endDate: string;
  subject: string;
  teacherId: number | null;
  scheduleType: string;
  status: string;
  notes: string | null;
  createdAt: string;
  updatedAt: string;
  canViewDetails?: boolean;
}

interface ClassroomItem {
  id: number;
  name: string;
  building: string;
  floor: number;
  roomType: string;
}

interface ClassItem {
  id: number;
  name: string;
  code: string;
}

interface ClassTeacherOption {
  id: number;
  userId: number;
  username?: string;
  name?: string;
  roleType: string;
  subject?: string | null;
}
/** 排班同步返回结果 */
interface ScheduleSyncResult {
  scheduleCount: number;
  shiftCount: number;
  groupCount: number;
  syncedItems: number;
  skippedNoMapping: number;
  failedBatchCount: number;
  failedItems: number;
  errors: string[];
  groups: Array<{ className: string; groupId: number; itemCount: number }>;
}

const WEEKDAYS = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
const WEEKDAY_NUMBERS = [1, 2, 3, 4, 5, 6, 7];

// ---- Component ----

const SchedulesPage: React.FC = () => {
  const { hasPermission } = usePermission();
  // View mode and navigation
  const [viewMode, setViewMode] = useState<'week' | 'month'>('week');
  const [viewDate, setViewDate] = useState<Dayjs>(() => dayjs().weekday(1).startOf('day'));

  // Modal date selection (month view)
  const [selectedDate, setSelectedDate] = useState<Dayjs | null>(null);

  // Data
  const [classrooms, setClassrooms] = useState<ClassroomItem[]>([]);
  const [classes, setClasses] = useState<ClassItem[]>([]);
  const [classTeachers, setClassTeachers] = useState<ClassTeacherOption[]>([]);
  const [matrix, setMatrix] = useState<Record<number, Record<number, ClassScheduleItem[]>>>({});
  const [loading, setLoading] = useState(false);

  // Filters
  const [filterClassroomIds, setFilterClassroomIds] = useState<number[]>([]);
  const [filterClassId, setFilterClassId] = useState<number | undefined>(undefined);

  // Modal
  const [modalOpen, setModalOpen] = useState(false);
  const [modalMode, setModalMode] = useState<'create' | 'edit' | 'detail'>('create');
  const [editingSchedule, setEditingSchedule] = useState<ClassScheduleItem | null>(null);
  const [selectedCell, setSelectedCell] = useState<{
    classroomId: number;
    weekDay: number;
  } | null>(null);
  const [selectedSchedules, setSelectedSchedules] = useState<ClassScheduleItem[]>([]);
  const [submitting, setSubmitting] = useState(false);

  // ── 钉钉排班同步 ──
  const [syncModalOpen, setSyncModalOpen] = useState(false);
  const [syncing, setSyncing] = useState(false);
  const [syncStatus, setSyncStatus] = useState<{
    activeSchedules: number;
    mappedClasses: number;
    totalClasses: number;
  } | null>(null);
  const [syncResult, setSyncResult] = useState<{
    scheduleCount: number;
    shiftCount: number;
    groupCount: number;
    syncedItems: number;
    skippedNoMapping: number;
    failedBatchCount: number;
    failedItems: number;
    errors: string[];
    groups: Array<{ className: string; groupId: number; itemCount: number }>;
  } | null>(null);
  const [syncDateFrom, setSyncDateFrom] = useState<Dayjs>(dayjs);
  const [syncDays, setSyncDays] = useState(30);
  const [attendanceMachineOnly, setAttendanceMachineOnly] = useState(false);

  /** 打开同步弹窗时先查询就绪状态 */
  const openSyncModal = useCallback(async () => {
    setSyncModalOpen(true);
    setSyncResult(null);
    try {
      const res = await api.get<{
        success: boolean;
        data: { activeSchedules: number; mappedClasses: number; totalClasses: number };
      }>('/sync/schedule/status');
      setSyncStatus(res.data);
    } catch {
      setSyncStatus(null);
    }
  }, []);

  /** 执行排班同步 */
  const handleSyncSchedule = useCallback(async () => {
    setSyncing(true);
    try {
      const res = await api.post<{
        success: boolean;
        data: ScheduleSyncResult;
      }>('/sync/schedule/sync', null, {
        params: {
          dateFrom: syncDateFrom.format('YYYY-MM-DD'),
          days: syncDays,
          attendanceMachineOnly,
        },
      });
      setSyncResult(res.data);
      const classification = classifySyncResult(res.data);
      if (classification.level === 'error') {
        message.error(classification.message);
      } else if (classification.level === 'warning') {
        message.warning(classification.message);
      } else {
        message.success(classification.message);
      }
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '同步失败');
    } finally {
      setSyncing(false);
    }
  }, [syncDateFrom, syncDays, attendanceMachineOnly]);
  const [form] = Form.useForm<ScheduleFormValues>();

  // Derived week/month info
  const weekStart = useMemo(() => viewDate.weekday(1).startOf('day'), [viewDate]);
  const monthStart = useMemo(() => viewDate.startOf('month'), [viewDate]);
  const weekEnd = useMemo(() => weekStart.add(6, 'day'), [weekStart]);
  const weekNum = useMemo(() => weekStart.week(), [weekStart]);
  const weekYear = useMemo(() => weekStart.year(), [weekStart]);
  const calendarDays = useMemo(() => {
    const monthEnd = monthStart.endOf('month');
    const startOffset = (monthStart.day() + 6) % 7;
    const endOffset = (7 - monthEnd.day()) % 7;
    const start = monthStart.subtract(startOffset, 'day');
    const end = monthEnd.add(endOffset, 'day');
    const totalDays = end.diff(start, 'day') + 1;
    const days: Dayjs[] = [];
    for (let i = 0; i < totalDays; i++) {
      days.push(start.add(i, 'day'));
    }
    return days;
  }, [monthStart]);

  const weeks = useMemo(() => {
    const result: Dayjs[][] = [];
    for (let i = 0; i < calendarDays.length; i += 7) {
      result.push(calendarDays.slice(i, i + 7));
    }
    return result;
  }, [calendarDays]);

  const startDateStr = useMemo(() => {
    if (viewMode === 'month') {
      return calendarDays[0].format('YYYY-MM-DD');
    }
    return weekStart.format('YYYY-MM-DD');
  }, [viewMode, weekStart, calendarDays]);

  const endDateStr = useMemo(() => {
    if (viewMode === 'month') {
      return calendarDays[calendarDays.length - 1].format('YYYY-MM-DD');
    }
    return weekEnd.format('YYYY-MM-DD');
  }, [viewMode, weekEnd, calendarDays]);

  // ---- Data fetching ----

  const fetchData = useCallback(async () => {
    setLoading(true);
    try {
      const [lookups, schedulesRes] = await Promise.all([
        api.get('/class-schedules/lookups') as Promise<{
          classrooms: ClassroomItem[];
          classes: ClassItem[];
        }>,
        api.get('/class-schedules/weekly', {
          params: {
            startDate: startDateStr,
            endDate: endDateStr,
            ...(filterClassroomIds.length === 1 ? { classroomId: filterClassroomIds[0] } : {}),
          },
        }) as Promise<Record<string, Record<string, ClassScheduleItem[]>>>,
      ]);

      setClassrooms(lookups.classrooms);
      setClasses(lookups.classes);

      // Convert string keys to numbers
      const typedMatrix: Record<number, Record<number, ClassScheduleItem[]>> = {};
      for (const [cId, dayMap] of Object.entries(schedulesRes)) {
        const classroomId = Number(cId);
        typedMatrix[classroomId] = {};
        for (const [wd, schedules] of Object.entries(dayMap)) {
          typedMatrix[classroomId][Number(wd)] = schedules;
        }
      }
      setMatrix(typedMatrix);
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '加载排课数据失败');
    } finally {
      setLoading(false);
    }
  }, [startDateStr, endDateStr, filterClassroomIds]);

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

  // ---- Filtered classrooms ----

  const filteredClassrooms = useMemo(() => {
    if (filterClassroomIds.length === 0) return classrooms;
    const idSet = new Set(filterClassroomIds);
    return classrooms.filter((c) => idSet.has(c.id));
  }, [classrooms, filterClassroomIds]);

  // Apply class filter to the matrix
  const displayMatrix = useMemo(() => {
    if (filterClassId == null) return matrix;
    const filtered: Record<number, Record<number, ClassScheduleItem[]>> = {};
    for (const [cId, dayMap] of Object.entries(matrix)) {
      const classroomId = Number(cId);
      filtered[classroomId] = {};
      for (const [wd, schedules] of Object.entries(dayMap)) {
        const matched = filterSchedulesForClass(schedules, filterClassId);
        if (matched.length > 0) {
          filtered[classroomId][Number(wd)] = matched;
        }
      }
    }
    return filtered;
  }, [matrix, filterClassId]);

  const monthScheduleMap = useMemo(() => {
    const map: Record<string, ClassScheduleItem[]> = {};
    for (const day of calendarDays) {
      const wd = day.day() === 0 ? 7 : day.day();
      const dateStr = day.format('YYYY-MM-DD');
      const result: ClassScheduleItem[] = [];
      for (const classroom of filteredClassrooms) {
        const daySchedules = displayMatrix[classroom.id]?.[wd] || [];
        for (const s of daySchedules) {
          if (dateStr >= s.startDate && dateStr <= s.endDate) {
            result.push(s);
          }
        }
      }
      map[dateStr] = result;
    }
    return map;
  }, [calendarDays, displayMatrix, filteredClassrooms]);

  // ---- Cell click handlers ----
  const handleCellClick = (classroomId: number, weekDay: number) => {
    const schedules = displayMatrix[classroomId]?.[weekDay] || [];
    setSelectedCell({ classroomId, weekDay });
    setSelectedDate(null);

    if (schedules.length > 0) {
      setSelectedSchedules(schedules);
      setModalMode('detail');
      setModalOpen(true);
    } else if (hasPermission('schedule:create')) {
      setSelectedSchedules([]);
      setEditingSchedule(null);
      setModalMode('create');
      form.resetFields();
      form.setFieldsValue({ classroomId, weekDay });
      setModalOpen(true);
    }
  };

  const getSchedulesForDate = (date: Dayjs): ClassScheduleItem[] => {
    const wd = date.day() === 0 ? 7 : date.day();
    const dateStr = date.format('YYYY-MM-DD');
    const result: ClassScheduleItem[] = [];
    for (const classroom of filteredClassrooms) {
      const daySchedules = displayMatrix[classroom.id]?.[wd] || [];
      for (const s of daySchedules) {
        if (dateStr >= s.startDate && dateStr <= s.endDate) {
          result.push(s);
        }
      }
    }
    return result;
  };

  const handleDateClick = (date: Dayjs) => {
    const dateKey = date.format('YYYY-MM-DD');
    const schedules = monthScheduleMap[dateKey] || getSchedulesForDate(date);
    setSelectedDate(date);
    setSelectedCell(null);
    setSelectedSchedules(schedules);
    setModalMode('detail');
    setModalOpen(true);
  };

  const loadClassTeachers = useCallback(async (classId: number) => {
    try {
      const teachers = await api.get<ClassTeacherOption[]>(
        `/class-schedules/classes/${classId}/teachers`,
      );
      setClassTeachers(teachers);
      return teachers;
    } catch {
      setClassTeachers([]);
      return [];
    }
  }, []);

  const applyClassTeacherDefaults = useCallback(
    async (classId: number, subject?: string) => {
      const teachers = await loadClassTeachers(classId);
      const subjectTeachers = teachers.filter((teacher) => teacher.roleType === 'subject_teacher');
      const matchedBySubject = subject
        ? subjectTeachers.filter((teacher) => teacher.subject && teacher.subject === subject)
        : [];
      const matched = matchedBySubject.length > 0 ? matchedBySubject : subjectTeachers;
      if (matched.length === 1) {
        form.setFieldValue('teacherId', matched[0].userId);
        if (!subject && matched[0].subject) form.setFieldValue('subject', matched[0].subject);
      } else {
        form.setFieldValue('teacherId', undefined);
      }
    },
    [form, loadClassTeachers],
  );

  // ---- Create / edit schedule ----

  const handleSubmit = async () => {
    if (modalMode === 'create' && !selectedCell) return;
    if (modalMode === 'edit' && !editingSchedule) return;
    try {
      const values = (await form.validateFields()) as ScheduleFormValues;
      setSubmitting(true);
      const payload = buildSchedulePayload(values);

      if (modalMode === 'edit' && editingSchedule) {
        await api.put(`/class-schedules/${editingSchedule.id}`, payload);
        message.success('排课更新成功，请重新同步到钉钉排班');
      } else {
        await api.post('/class-schedules', payload);
        message.success('排课创建成功');
      }
      setModalOpen(false);
      setEditingSchedule(null);
      fetchData();
    } catch (e: unknown) {
      const err = e as { message?: string; status?: number };
      message.error(err?.message || (modalMode === 'edit' ? '更新排课失败' : '创建排课失败'));
    } finally {
      setSubmitting(false);
    }
  };

  const openEditSchedule = (schedule: ClassScheduleItem) => {
    if (isMaskedSchedule(schedule) || schedule.id === null || schedule.classId === null) return;
    if (schedule.scheduleType === 'RENTAL') {
      message.warning('租赁排课请在租赁订单中修改');
      return;
    }
    const editableSchedule = { ...schedule, id: schedule.id, classId: schedule.classId };
    setEditingSchedule(schedule);
    setModalMode('edit');
    form.setFieldsValue(scheduleToFormValues(editableSchedule));
    void loadClassTeachers(editableSchedule.classId);
  };

  // ---- Delete schedule ----

  const handleDelete = async (id: number | null) => {
    if (id === null) return;
    try {
      await api.delete(`/class-schedules/${id}`);
      message.success('排课已删除');
      // Refresh the displayed schedules
      const remaining = selectedSchedules.filter((s) => s.id !== id);
      setSelectedSchedules(remaining);
      if (remaining.length === 0) {
        setModalOpen(false);
      }
      fetchData();
    } catch (e: unknown) {
      const err = e as { message?: string };
      message.error(err?.message || '删除失败');
    }
  };

  // ---- Classroom select options ----

  const classroomOptions = useMemo(
    () =>
      classrooms.map((c) => ({
        value: c.id,
        label: `${c.building ? c.building + ' · ' : ''}${c.name}`,
      })),
    [classrooms],
  );

  const classOptions = useMemo(
    () =>
      classes.map((c) => ({
        value: c.id,
        label: `${c.name}${c.code ? ` (${c.code})` : ''}`,
      })),
    [classes],
  );

  // ---- Render ----

  const selectedClassroom = selectedCell
    ? classrooms.find((c) => c.id === selectedCell.classroomId)
    : undefined;

  return (
    <div>
      {/* Header */}
      <div
        style={{
          marginBottom: 16,
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          flexWrap: 'wrap',
          gap: 8,
        }}
      >
        <Space>
          <CalendarOutlined style={{ fontSize: 20 }} />
          <h3 style={{ margin: 0 }}>排课管理</h3>
        </Space>
        <Space>
          <Segmented
            value={viewMode}
            onChange={(v) => {
              setViewMode(v as 'week' | 'month');
              setSelectedDate(null);
            }}
            options={[
              { label: '周视图', value: 'week' },
              { label: '月视图', value: 'month' },
            ]}
          />
          <PermissionButton
            permission="sync:trigger"
            type="primary"
            icon={<CloudSyncOutlined />}
            onClick={openSyncModal}
          >
            同步到钉钉排班
          </PermissionButton>
          {viewMode === 'week' ? (
            <>
              <Button
                icon={<LeftOutlined />}
                onClick={() => setViewDate(viewDate.subtract(7, 'day'))}
              >
                上一周
              </Button>
              <span style={{ fontWeight: 500, fontSize: 15 }}>
                {weekYear} W{weekNum}
                <span style={{ color: '#8c8c8c', fontWeight: 400, fontSize: 13, marginLeft: 6 }}>
                  ({startDateStr} ~ {endDateStr})
                </span>
              </span>
              <Button icon={<RightOutlined />} onClick={() => setViewDate(viewDate.add(7, 'day'))}>
                下一周
              </Button>
            </>
          ) : (
            <>
              <Button
                icon={<LeftOutlined />}
                onClick={() => setViewDate(viewDate.subtract(1, 'month'))}
              >
                上一月
              </Button>
              <span style={{ fontWeight: 500, fontSize: 15 }}>
                {monthStart.format('YYYY年 M月')}
              </span>
              <Button
                icon={<RightOutlined />}
                onClick={() => setViewDate(viewDate.add(1, 'month'))}
              >
                下一月
              </Button>
            </>
          )}
        </Space>
      </div>

      {/* Filters */}
      <Card size="small" style={{ marginBottom: 16 }}>
        <Space wrap>
          <Select
            mode="multiple"
            placeholder="筛选教室"
            allowClear
            style={{ minWidth: 200 }}
            value={filterClassroomIds}
            onChange={(v) => setFilterClassroomIds(v)}
            options={classroomOptions}
            maxTagCount={3}
          />
          <Select
            placeholder="筛选班级"
            allowClear
            style={{ minWidth: 160 }}
            value={filterClassId}
            onChange={(v) => setFilterClassId(v)}
            options={classOptions}
          />
        </Space>
      </Card>

      {/* Matrix */}
      <Spin spinning={loading}>
        {classrooms.length === 0 ? (
          <Empty description="暂无教室数据" />
        ) : viewMode === 'week' ? (
          <div style={{ overflowX: 'auto' }}>
            <table
              style={{
                width: '100%',
                borderCollapse: 'collapse',
                fontSize: 13,
                tableLayout: 'fixed',
              }}
            >
              <thead>
                <tr style={{ background: '#fafafa' }}>
                  <th
                    style={{
                      position: 'sticky',
                      left: 0,
                      background: '#fafafa',
                      zIndex: 2,
                      padding: '10px 12px',
                      border: '1px solid #f0f0f0',
                      width: 150,
                      textAlign: 'left',
                    }}
                  >
                    教室
                  </th>
                  {WEEKDAYS.map((day) => (
                    <th
                      key={day}
                      style={{
                        padding: '10px 8px',
                        border: '1px solid #f0f0f0',
                        textAlign: 'center',
                        background: '#fafafa',
                        fontWeight: 500,
                      }}
                    >
                      {day}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {filteredClassrooms.map((classroom) => (
                  <tr key={classroom.id}>
                    <td
                      style={{
                        position: 'sticky',
                        left: 0,
                        background: '#fff',
                        zIndex: 1,
                        padding: '8px 12px',
                        border: '1px solid #f0f0f0',
                        fontWeight: 500,
                      }}
                    >
                      <div>{classroom.name}</div>
                      {classroom.building && (
                        <div style={{ fontSize: 11, color: '#8c8c8c', marginTop: 2 }}>
                          {classroom.building}
                          {classroom.floor ? ` ${classroom.floor}F` : ''}
                        </div>
                      )}
                    </td>
                    {WEEKDAY_NUMBERS.map((wd) => {
                      const schedules = displayMatrix[classroom.id]?.[wd] || [];
                      const hasContent = schedules.length > 0;
                      return (
                        <td
                          key={wd}
                          tabIndex={0}
                          role="button"
                          aria-label={`选择教室 ${classroom.name} ${WEEKDAYS[wd - 1]} 排课`}
                          onClick={() => handleCellClick(classroom.id, wd)}
                          onKeyDown={(e) => {
                            if (e.key === 'Enter' || e.key === ' ') {
                              e.preventDefault();
                              handleCellClick(classroom.id, wd);
                            }
                          }}
                          style={{
                            padding: 4,
                            border: '1px solid #f0f0f0',
                            verticalAlign: 'top',
                            cursor: 'pointer',
                            minHeight: 56,
                            transition: 'background 0.15s',
                          }}
                          onMouseEnter={(e) => {
                            (e.currentTarget as HTMLElement).style.background = '#f6f8fa';
                          }}
                          onMouseLeave={(e) => {
                            (e.currentTarget as HTMLElement).style.background = '';
                          }}
                        >
                          {hasContent ? (
                            <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                              {schedules.map((s) => (
                                <Tooltip
                                  key={`${s.id ?? 'busy'}-${s.classroomId}-${s.weekDay}-${s.startTime}-${s.endTime}`}
                                  title={
                                    isMaskedSchedule(s)
                                      ? `已占用 · ${s.startTime}-${s.endTime}`
                                      : `${s.subject} · ${s.startTime}-${s.endTime} · ${s.startDate}~${s.endDate}`
                                  }
                                >
                                  <div
                                    style={{
                                      background: isMaskedSchedule(s) ? '#f5f5f5' : '#e6f4ff',
                                      border: isMaskedSchedule(s)
                                        ? '1px solid #d9d9d9'
                                        : '1px solid #91caff',
                                      borderRadius: 4,
                                      padding: '2px 6px',
                                      fontSize: 12,
                                      lineHeight: '18px',
                                    }}
                                  >
                                    <div
                                      style={{
                                        fontWeight: 600,
                                        color: isMaskedSchedule(s) ? '#595959' : '#1677ff',
                                      }}
                                    >
                                      {s.subject}
                                    </div>
                                    <div style={{ color: '#595959' }}>
                                      {s.startTime}-{s.endTime}
                                    </div>
                                  </div>
                                </Tooltip>
                              ))}
                            </div>
                          ) : (
                            <div
                              style={{
                                color: '#d9d9d9',
                                fontSize: 20,
                                textAlign: 'center',
                                lineHeight: '44px',
                              }}
                            >
                              —
                            </div>
                          )}
                        </td>
                      );
                    })}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        ) : (
          <div style={{ overflowX: 'auto' }}>
            <table
              style={{
                width: '100%',
                borderCollapse: 'collapse',
                fontSize: 13,
                tableLayout: 'fixed',
              }}
            >
              <thead>
                <tr style={{ background: '#fafafa' }}>
                  {['周一', '周二', '周三', '周四', '周五', '周六', '周日'].map((d) => (
                    <th
                      key={d}
                      style={{
                        padding: '10px 8px',
                        border: '1px solid #f0f0f0',
                        textAlign: 'center',
                        fontWeight: 500,
                      }}
                    >
                      {d}
                    </th>
                  ))}
                </tr>
              </thead>
              <tbody>
                {weeks.map((week, wi) => (
                  <tr key={wi}>
                    {week.map((day, di) => {
                      const isCurrentMonth = day.month() === monthStart.month();
                      const dateKey = day.format('YYYY-MM-DD');
                      const daySchedules = monthScheduleMap[dateKey] || [];
                      const count = daySchedules.length;
                      return (
                        <td
                          key={di}
                          tabIndex={0}
                          role="button"
                          aria-label={`${day.format('YYYY-MM-DD')} 排课详情`}
                          onClick={() => handleDateClick(day)}
                          onKeyDown={(e) => {
                            if (e.key === 'Enter' || e.key === ' ') {
                              e.preventDefault();
                              handleDateClick(day);
                            }
                          }}
                          style={{
                            padding: '6px 8px',
                            border: '1px solid #f0f0f0',
                            verticalAlign: 'top',
                            cursor: 'pointer',
                            height: 90,
                            background: isCurrentMonth ? '#fff' : '#fafafa',
                            transition: 'background 0.15s',
                          }}
                          onMouseEnter={(e) => {
                            (e.currentTarget as HTMLElement).style.background = isCurrentMonth
                              ? '#f0f5ff'
                              : '#f0f0f0';
                          }}
                          onMouseLeave={(e) => {
                            (e.currentTarget as HTMLElement).style.background = isCurrentMonth
                              ? ''
                              : '#fafafa';
                          }}
                        >
                          <div
                            style={{
                              fontWeight: isCurrentMonth ? 600 : 400,
                              color: isCurrentMonth ? '#262626' : '#bfbfbf',
                              fontSize: 14,
                              marginBottom: 4,
                            }}
                          >
                            {day.date()}
                          </div>
                          {count > 0 && (
                            <Badge
                              count={count}
                              size="small"
                              overflowCount={99}
                              style={{ backgroundColor: '#1677ff' }}
                            />
                          )}
                        </td>
                      );
                    })}
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </Spin>

      {/* Modal */}
      <Modal
        title={
          modalMode === 'create'
            ? `新增排课 — ${selectedClassroom?.name || ''} · ${selectedCell ? WEEKDAYS[selectedCell.weekDay - 1] : ''}`
            : modalMode === 'edit'
              ? `编辑排课 — ${editingSchedule?.subject || ''}`
              : selectedDate
                ? `排课详情 — ${selectedDate.format('YYYY-MM-DD')} ${WEEKDAYS[selectedDate.day() === 0 ? 6 : selectedDate.day() - 1]}`
                : `排课详情 — ${selectedClassroom?.name || ''} · ${selectedCell ? WEEKDAYS[selectedCell.weekDay - 1] : ''}`
        }
        open={modalOpen}
        onCancel={() => {
          setModalOpen(false);
          setEditingSchedule(null);
        }}
        onOk={modalMode !== 'detail' ? handleSubmit : undefined}
        confirmLoading={submitting}
        okText={modalMode === 'edit' ? '保存' : modalMode === 'create' ? '创建' : undefined}
        footer={modalMode === 'detail' ? null : undefined}
        width={600}
        destroyOnHidden
      >
        {modalMode !== 'detail' ? (
          <Form form={form} layout="vertical" style={{ marginTop: 16 }}>
            <Form.Item
              name="classId"
              label="班级"
              rules={[{ required: true, message: '请选择班级' }]}
            >
              <Select
                placeholder="选择班级"
                showSearch
                optionFilterProp="label"
                options={classOptions}
                onChange={(classId: number) => {
                  form.setFieldValue('teacherId', undefined);
                  void applyClassTeacherDefaults(classId, form.getFieldValue('subject'));
                }}
              />
            </Form.Item>

            <Form.Item
              name="classroomId"
              label="教室"
              rules={[{ required: true, message: '请选择教室' }]}
            >
              <Select
                placeholder="选择教室"
                showSearch
                optionFilterProp="label"
                options={classroomOptions}
              />
            </Form.Item>

            <Form.Item
              name="weekDay"
              label="星期"
              rules={[{ required: true, message: '请选择星期' }]}
            >
              <Select
                options={WEEKDAY_NUMBERS.map((value) => ({ value, label: WEEKDAYS[value - 1] }))}
              />
            </Form.Item>

            <Form.Item
              name="subject"
              label="科目"
              rules={[{ required: true, message: '请输入科目' }]}
            >
              <Input
                placeholder="如：数学、语文"
                onBlur={(event) => {
                  const classId = form.getFieldValue('classId');
                  if (classId) void applyClassTeacherDefaults(classId, event.target.value);
                }}
              />
            </Form.Item>

            <Form.Item name="teacherId" label="任课老师">
              <Select
                showSearch
                allowClear
                placeholder="先选班级；系统会按科目自动带出任课老师"
                optionFilterProp="label"
                options={classTeachers.map((teacher) => ({
                  value: teacher.userId,
                  label: `${teacher.name || teacher.username || `#${teacher.userId}`}${teacher.subject ? ` · ${teacher.subject}` : ''}`,
                }))}
                notFoundContent="该班级暂无可选教师，请先在班级详情配置教师"
              />
            </Form.Item>

            <Form.Item
              name="timeRange"
              label="上课时段"
              rules={[{ required: true, message: '请选择时段' }]}
            >
              <TimePicker.RangePicker
                format="HH:mm"
                minuteStep={10}
                style={{ width: '100%' }}
                placeholder={['开始时间', '结束时间']}
              />
            </Form.Item>

            <Form.Item
              name="dateRange"
              label="日期范围"
              rules={[{ required: true, message: '请选择日期范围' }]}
            >
              <DatePicker.RangePicker
                style={{ width: '100%' }}
                placeholder={['开始日期', '结束日期']}
              />
            </Form.Item>
          </Form>
        ) : (
          <div style={{ lineHeight: 2 }}>
            <div
              style={{
                marginBottom: 12,
                display: 'flex',
                justifyContent: 'space-between',
                alignItems: 'center',
              }}
            >
              <span style={{ fontWeight: 500 }}>已有排课</span>
              <PermissionButton
                permission="schedule:create"
                type="primary"
                icon={<PlusOutlined />}
                onClick={() => {
                  setEditingSchedule(null);
                  setModalMode('create');
                  form.resetFields();
                  form.setFieldsValue({
                    classroomId: selectedCell?.classroomId,
                    weekDay:
                      selectedCell?.weekDay ?? (selectedDate ? selectedDate.day() || 7 : undefined),
                    dateRange: selectedDate ? [selectedDate, selectedDate] : undefined,
                  });
                }}
              >
                新增排课
              </PermissionButton>
            </div>
            {selectedSchedules.length === 0 ? (
              <Empty description="该时段暂无排课" />
            ) : (
              selectedSchedules.map((s) => (
                <Card
                  key={`${s.id ?? 'busy'}-${s.classroomId}-${s.weekDay}-${s.startTime}-${s.endTime}`}
                  size="small"
                  style={{ marginBottom: 8 }}
                  styles={{ body: { padding: 12 } }}
                >
                  <div
                    style={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'flex-start',
                    }}
                  >
                    <div>
                      <div>
                        <strong>{isMaskedSchedule(s) ? '状态：' : '科目：'}</strong>
                        <Tag color={isMaskedSchedule(s) ? 'default' : 'blue'}>{s.subject}</Tag>
                      </div>
                      {!isMaskedSchedule(s) && (
                        <div>
                          <strong>班级：</strong>
                          {classes.find((c) => c.id === s.classId)?.name || `#${s.classId}`}
                        </div>
                      )}
                      {!isMaskedSchedule(s) && s.teacherId != null && (
                        <div>
                          <strong>教师：</strong>
                          {classTeachers.find((u) => u.userId === s.teacherId)?.name ||
                            classTeachers.find((u) => u.userId === s.teacherId)?.username ||
                            `#${s.teacherId}`}
                        </div>
                      )}
                      <div>
                        <strong>时段：</strong>
                        {s.startTime} ~ {s.endTime}
                      </div>
                      <div>
                        <strong>日期：</strong>
                        {s.startDate} ~ {s.endDate}
                      </div>
                      {!isMaskedSchedule(s) && s.notes && (
                        <div>
                          <strong>备注：</strong>
                          {s.notes}
                        </div>
                      )}
                      {!isMaskedSchedule(s) && (
                        <div>
                          <Tag color={s.scheduleType === 'RENTAL' ? 'orange' : 'green'}>
                            {s.scheduleType === 'RENTAL' ? '租赁' : '内部'}
                          </Tag>
                          <Tag color={s.status === 'active' ? 'green' : 'default'}>{s.status}</Tag>
                        </div>
                      )}
                    </div>
                    {!isMaskedSchedule(s) && (
                      <Space>
                        {s.scheduleType !== 'RENTAL' && (
                          <PermissionButton
                            permission="schedule:edit"
                            size="small"
                            icon={<EditOutlined />}
                            onClick={() => openEditSchedule(s)}
                          >
                            编辑
                          </PermissionButton>
                        )}
                        <Popconfirm
                          title="确认删除该排课？"
                          onConfirm={() => handleDelete(s.id)}
                          okText="删除"
                          cancelText="取消"
                        >
                          <PermissionButton
                            permission="schedule:delete"
                            size="small"
                            danger
                            icon={<DeleteOutlined />}
                          >
                            删除
                          </PermissionButton>
                        </Popconfirm>
                      </Space>
                    )}
                  </div>
                </Card>
              ))
            )}
          </div>
        )}
      </Modal>

      {/* ── 钉钉排班同步 Modal ── */}
      <Modal
        title="同步排课到钉钉考勤排班"
        open={syncModalOpen}
        onCancel={() => {
          setSyncModalOpen(false);
          setSyncResult(null);
        }}
        footer={
          syncResult
            ? [
                <Button
                  key="close"
                  onClick={() => {
                    setSyncModalOpen(false);
                    setSyncResult(null);
                  }}
                >
                  关闭
                </Button>,
              ]
            : [
                <Button
                  key="cancel"
                  onClick={() => {
                    setSyncModalOpen(false);
                    setSyncResult(null);
                  }}
                >
                  取消
                </Button>,
                <Button
                  key="sync"
                  type="primary"
                  icon={<CloudSyncOutlined />}
                  loading={syncing}
                  onClick={handleSyncSchedule}
                  disabled={!syncStatus || syncStatus.activeSchedules === 0}
                >
                  开始同步
                </Button>,
              ]
        }
        width={560}
      >
        {syncResult ? (
          /* ── 同步结果 ── */
          <div>
            <Row gutter={16} style={{ marginBottom: 16 }}>
              <Col span={6}>
                <Statistic title="排课" value={syncResult.scheduleCount} suffix="条" />
              </Col>
              <Col span={6}>
                <Statistic title="班次" value={syncResult.shiftCount} suffix="个" />
              </Col>
              <Col span={6}>
                <Statistic title="考勤组" value={syncResult.groupCount} suffix="个" />
              </Col>
              <Col span={6}>
                <Statistic
                  title="排班数"
                  value={syncResult.syncedItems}
                  suffix="条"
                  valueStyle={{ color: '#3f8600' }}
                />
              </Col>
            </Row>
            {syncResult.skippedNoMapping > 0 && (
              <Alert
                type="warning"
                message={`${syncResult.skippedNoMapping} 条排课因班级无钉钉绑定学生而跳过`}
                style={{ marginBottom: 16 }}
                showIcon
              />
            )}
            {syncResult.failedBatchCount > 0 && (
              <>
                <Alert
                  type="error"
                  message={`${syncResult.failedBatchCount} 批写入失败，共 ${syncResult.failedItems} 条`}
                  description={
                    syncResult.errors.length > 0
                      ? syncResult.errors.slice(0, 5).map((err, i) => (
                          <div key={i} style={{ wordBreak: 'break-all' }}>
                            {err}
                          </div>
                        ))
                      : undefined
                  }
                  style={{ marginBottom: 16 }}
                  showIcon
                />
                {syncResult.errors.length > 5 && (
                  <div style={{ fontSize: 12, color: '#999', marginBottom: 16, marginTop: -12 }}>
                    ...以及其他 {syncResult.errors.length - 5} 条错误
                  </div>
                )}
              </>
            )}
            {syncResult.groups.length > 0 && (
              <div>
                <div style={{ fontWeight: 500, marginBottom: 8 }}>按班级分组：</div>
                {syncResult.groups.map((g) => (
                  <Tag key={g.groupId} color="blue" style={{ marginBottom: 4 }}>
                    {g.className}：{g.itemCount} 条排班
                  </Tag>
                ))}
              </div>
            )}
          </div>
        ) : syncStatus ? (
          /* ── 同步确认信息 ── */
          <div>
            <Row gutter={16} style={{ marginBottom: 16 }}>
              <Col span={8}>
                <Statistic title="活跃排课" value={syncStatus.activeSchedules} suffix="条" />
              </Col>
              <Col span={8}>
                <Statistic
                  title="已就绪班级"
                  value={syncStatus.mappedClasses}
                  suffix={`/ ${syncStatus.totalClasses}`}
                  valueStyle={{
                    color:
                      syncStatus.mappedClasses < syncStatus.totalClasses ? '#faad14' : '#3f8600',
                  }}
                />
              </Col>
              <Col span={8}>
                <Statistic
                  title="无绑定学生班级"
                  value={syncStatus.totalClasses - syncStatus.mappedClasses}
                  suffix="个"
                />
              </Col>
            </Row>
            {syncStatus.mappedClasses < syncStatus.totalClasses && (
              <Alert
                type="warning"
                message={`${syncStatus.totalClasses - syncStatus.mappedClasses} 个班级没有已绑定钉钉的学生，其排课将被跳过。请先在钉钉集成页导入并绑定学生。`}
                style={{ marginBottom: 16 }}
                showIcon
              />
            )}
            <div style={{ marginBottom: 16 }}>
              <div style={{ marginBottom: 8, fontWeight: 500 }}>同步参数</div>
              <Space wrap>
                <span>起始日期：</span>
                <DatePicker
                  value={syncDateFrom}
                  onChange={(d) => d && setSyncDateFrom(d)}
                  allowClear={false}
                />
                <span>天数：</span>
                <Select
                  value={syncDays}
                  onChange={setSyncDays}
                  style={{ width: 100 }}
                  options={[
                    { value: 7, label: '7 天' },
                    { value: 14, label: '14 天' },
                    { value: 30, label: '30 天' },
                    { value: 60, label: '60 天' },
                    { value: 90, label: '90 天' },
                  ]}
                />
              </Space>
              <div style={{ marginTop: 16 }}>
                <Space align="start">
                  <Switch checked={attendanceMachineOnly} onChange={setAttendanceMachineOnly} />
                  <div>
                    <div style={{ fontWeight: 500 }}>仅允许考勤机打卡</div>
                    <div style={{ color: '#8c8c8c', fontSize: 12, marginTop: 2 }}>
                      开启后将关闭外勤、定位、Wi-Fi 和手机蓝牙打卡，并禁止无排班打卡。
                    </div>
                  </div>
                </Space>
              </div>
              {attendanceMachineOnly && (
                <Alert
                  type="info"
                  showIcon
                  message="已存在的同名考勤组也会在本次同步中更新为仅考勤机打卡。"
                  style={{ marginTop: 12 }}
                />
              )}
            </div>
            {syncStatus.activeSchedules === 0 && (
              <Alert
                type="info"
                message="当前没有活跃排课。请先在排课页面创建排课记录。"
                showIcon
              />
            )}
          </div>
        ) : (
          <Spin tip="查询同步状态..." />
        )}
      </Modal>
    </div>
  );
};

export default SchedulesPage;
