/**
 * 课程表主屏幕
 * 参考哈课表APP的设计风格
 */

import React, { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ScrollView,
  TouchableOpacity,
  Dimensions,
  StatusBar,
  Modal,
  TextInput,
  Alert,
  ActivityIndicator,
} from 'react-native';
import { PanGestureHandler, State } from 'react-native-gesture-handler';
import type { PanGestureHandlerStateChangeEvent } from 'react-native-gesture-handler';
import { SafeAreaView } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { useFocusEffect, useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { colors, fontSizes, spacing, borderRadius, shadows } from '../../theme';
import {
  Course,
  COURSE_COLORS,
  TimeSlot,
  getCourseColor,
  hasCourseInWeek,
} from '../../types/schedule';
import type { ScheduleStackParamList } from '../../navigation/types';
import { scheduleService } from '../../services/scheduleService';

const { width: SCREEN_WIDTH } = Dimensions.get('window');

// 时间段列宽度（按需求缩短）
const TIME_COLUMN_WIDTH = 38;
const VISIBLE_DAY_VALUES = [0, 1, 2, 3, 4, 5, 6]; // 周一到周日（0=周一）
const VISIBLE_WEEKDAY_NAMES = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
// 星期列宽度（根据屏幕宽度自动计算）
const getDayColumnWidth = () => Math.max(46, (SCREEN_WIDTH - TIME_COLUMN_WIDTH - 2) / VISIBLE_DAY_VALUES.length);

// 每个大节（两小节）高度
const SECTION_HEIGHT = 105;
// 顶部周选择器高度
const WEEK_SELECTOR_HEIGHT = 44;
// 星期标题行高度
const HEADER_HEIGHT = 40;
// 底部Tab栏高度（用于避让）
const TAB_BAR_HEIGHT = 80;

// 大节时间配置（左侧显示 1-6）
const GROUPED_TIME_SLOTS: TimeSlot[] = [
  { section: 1, startTime: '8:00', endTime: '9:45' },
  { section: 2, startTime: '10:05', endTime: '11:50' },
  { section: 3, startTime: '14:00', endTime: '15:45' },
  { section: 4, startTime: '16:05', endTime: '17:50' },
  { section: 5, startTime: '18:40', endTime: '20:25' },
  { section: 6, startTime: '20:45', endTime: '22:30' },
];

const getMergedSectionIndex = (section: number) => Math.ceil(section / 2);
const MAX_COURSE_NAME_CHARS = 11;
const formatCourseName = (name: string) =>
  name.length > MAX_COURSE_NAME_CHARS ? `${name.slice(0, MAX_COURSE_NAME_CHARS)}…` : name;
const MERGED_SECTION_COUNT = GROUPED_TIME_SLOTS.length;
const getMergedSectionStart = (mergedSection: number) => (mergedSection - 1) * 2 + 1;
const getMergedSectionEnd = (mergedSection: number) => mergedSection * 2;
const SWIPE_THRESHOLD = 18;

type RepeatMode = 'single' | 'weekly' | 'odd' | 'even';
type CourseDisplayItem = {
  key: string;
  course: Course;
  locationText: string;
  laneIndex: number;
  laneCount: number;
};
const TOTAL_WEEKS = 20;
const HEX_COLOR_REGEX = /^#?[0-9A-Fa-f]{6}$/;
const parseWeekInput = (value: string, fallback: number) => {
  const parsed = Number.parseInt(value, 10);
  if (Number.isNaN(parsed)) return fallback;
  return Math.min(Math.max(parsed, 1), TOTAL_WEEKS);
};
const normalizeHexColor = (value: string) => {
  const trimmed = value.trim();
  if (!trimmed) return '';
  if (!HEX_COLOR_REGEX.test(trimmed)) return '';
  return (trimmed.startsWith('#') ? trimmed : `#${trimmed}`).toUpperCase();
};

// 获取今天在课表中的列索引（周一=0 ... 周日=6）
const getTodayColumnIndex = () => {
  const day = new Date().getDay();
  // day: 0=周日, 1=周一, ..., 6=周六
  // 映射到: 周一=0, 周二=1, ..., 周六=5, 周日=6
  if (day === 0) return 6; // 周日在最后
  return day - 1;
};

// 第1周固定从2026年3月9日（周一）开始
const FIRST_WEEK_START = new Date(2026, 2, 9); // 2026年3月9日

// 获取指定周的起始日期、每天的日期和月份
// weekIndex: 0表示第1周，1表示第2周，以此类推
const getWeekInfo = (weekIndex: number = 0) => {
  // 计算该周的周一日期
  const monday = new Date(FIRST_WEEK_START);
  monday.setDate(monday.getDate() + weekIndex * 7);
  
  const dates = [];
  for (let i = 0; i < 7; i++) {
    const date = new Date(monday);
    date.setDate(monday.getDate() + i);
    dates.push(date.getDate());
  }
  
  // 获取该周周一所在的月份
  const month = monday.getMonth() + 1;
  
  return { dates, month };
};

// 为了向后兼容，保留 getWeekDates 函数
const getWeekDates = (weekOffset: number = 0) => {
  return getWeekInfo(weekOffset).dates;
};

export const ScheduleScreen: React.FC = () => {
  const navigation = useNavigation<NativeStackNavigationProp<ScheduleStackParamList>>();
  const [currentWeek, setCurrentWeek] = useState(1);
  const [courses, setCourses] = useState<Course[]>([]);
  const [isAddModalVisible, setIsAddModalVisible] = useState(false);
  const [pendingDay, setPendingDay] = useState<number>(0);
  const [pendingMergedSection, setPendingMergedSection] = useState<number>(1);
  const [newCourseName, setNewCourseName] = useState('');
  const [newCourseTeacher, setNewCourseTeacher] = useState('');
  const [newCourseLocation, setNewCourseLocation] = useState('');
  const [newCourseColor, setNewCourseColor] = useState('');
  const [repeatMode, setRepeatMode] = useState<RepeatMode>('single');
  const [startWeekInput, setStartWeekInput] = useState(String(currentWeek));
  const [endWeekInput, setEndWeekInput] = useState(String(TOTAL_WEEKS));
  const weekScrollRef = useRef<ScrollView | null>(null);

  // 设置弹窗状态
  const [isSettingsModalVisible, setIsSettingsModalVisible] = useState(false);
  // 同步教务系统弹窗状态
  const [isSyncModalVisible, setIsSyncModalVisible] = useState(false);
  const [syncUsername, setSyncUsername] = useState('');
  const [syncPassword, setSyncPassword] = useState('');
  const [isSyncing, setIsSyncing] = useState(false);
  const todayColumnIndex = getTodayColumnIndex();
  // currentWeek === 1 对应今天所在的真实周（offset 0），其他周不高亮今日列
  const isViewingCurrentWeek = currentWeek === 1;
  const activeTodayColumn = isViewingCurrentWeek ? todayColumnIndex : -1;

  const dayColumnWidth = getDayColumnWidth();
  const usedCourseColors = useMemo(
    () => new Set(courses.map(item => normalizeHexColor(item.color || '')).filter(Boolean)),
    [courses]
  );
  const suggestColor = useCallback(() => {
    const firstAvailable = COURSE_COLORS.find(color => !usedCourseColors.has(normalizeHexColor(color)));
    if (firstAvailable) return normalizeHexColor(firstAvailable);
    return '';
  }, [usedCourseColors]);

  const loadCourses = useCallback(async () => {
    try {
      const remoteCourses = await scheduleService.getCourses();
      setCourses(remoteCourses);
    } catch (error) {
      console.error('加载课表失败:', error);
      Alert.alert('加载失败', '获取课表数据失败，请稍后重试');
    }
  }, []);

  // 生成周数列表
  const weeks = useMemo(() => {
    return Array.from({ length: TOTAL_WEEKS }, (_, i) => i + 1);
  }, []);

  useEffect(() => {
    const WEEK_ITEM_ESTIMATED_WIDTH = 92;
    const centerOffset = SCREEN_WIDTH / 2 - WEEK_ITEM_ESTIMATED_WIDTH / 2 - 40;
    const targetX = Math.max(0, (currentWeek - 1) * WEEK_ITEM_ESTIMATED_WIDTH - centerOffset);
    weekScrollRef.current?.scrollTo({ x: targetX, animated: true });
  }, [currentWeek]);

  useFocusEffect(
    useCallback(() => {
      loadCourses();
    }, [loadCourses])
  );

  // 获取当前周的课程
  const getCurrentWeekCourses = useCallback(() => {
    return courses.filter(course => hasCourseInWeek(course, currentWeek));
  }, [courses, currentWeek]);

  const getRelatedCourses = useCallback(
    (targetCourse: Course) => {
      return courses
        .filter(course => course.name === targetCourse.name)
        .sort((a, b) => {
          if (a.dayOfWeek !== b.dayOfWeek) return a.dayOfWeek - b.dayOfWeek;
          return a.startSection - b.startSection;
        });
    },
    [courses]
  );

  const handleWeekSwipe = useCallback(
    ({ nativeEvent }: PanGestureHandlerStateChangeEvent) => {
      if (nativeEvent.oldState !== State.ACTIVE && nativeEvent.oldState !== State.BEGAN) return;
      const { translationX, translationY } = nativeEvent;
      if (Math.abs(translationX) < SWIPE_THRESHOLD) return;
      if (Math.abs(translationX) <= Math.abs(translationY) * 0.8) return;

      if (translationX < 0) {
        setCurrentWeek(prev => Math.min(prev + 1, weeks.length));
      } else {
        setCurrentWeek(prev => Math.max(prev - 1, 1));
      }
    },
    [weeks.length]
  );

  const isSlotOccupied = useCallback(
    (dayOfWeek: number, mergedSection: number, weekCourses: Course[]) => {
      return weekCourses.some(course => {
        if (course.dayOfWeek !== dayOfWeek) return false;
        const start = getMergedSectionIndex(course.startSection);
        const end = getMergedSectionIndex(course.endSection);
        return mergedSection >= start && mergedSection <= end;
      });
    },
    []
  );

  const openAddCourseModal = useCallback((dayOfWeek: number, mergedSection: number) => {
    setPendingDay(dayOfWeek);
    setPendingMergedSection(mergedSection);
    setNewCourseName('');
    setNewCourseTeacher('');
    setNewCourseLocation('');
    setNewCourseColor(suggestColor());
    setRepeatMode('single');
    setStartWeekInput(String(currentWeek));
    setEndWeekInput(String(TOTAL_WEEKS));
    setIsAddModalVisible(true);
  }, [currentWeek, suggestColor]);

  const closeAddCourseModal = useCallback(() => {
    setIsAddModalVisible(false);
  }, []);

  const confirmAddCourse = useCallback(async () => {
    const name = newCourseName.trim();
    if (!name) return;

    const startSection = getMergedSectionStart(pendingMergedSection);
    const endSection = getMergedSectionEnd(pendingMergedSection);
    const startWeek = parseWeekInput(startWeekInput, currentWeek);
    const endWeek = parseWeekInput(endWeekInput, TOTAL_WEEKS);
    const normalizedStartWeek = Math.min(startWeek, endWeek);
    const normalizedEndWeek = Math.max(startWeek, endWeek);

    const repeatWeeks = weeks.filter(week => {
      if (week < normalizedStartWeek || week > normalizedEndWeek) return false;
      if (repeatMode === 'single') return week === currentWeek;
      if (repeatMode === 'weekly') return true;
      if (repeatMode === 'odd') return week % 2 === 1;
      return week % 2 === 0;
    });

    const normalizedColor = normalizeHexColor(newCourseColor);
    if (!normalizedColor) {
      Alert.alert('颜色无效', '请输入有效的颜色值，例如 #FF6B6B');
      return;
    }
    if (usedCourseColors.has(normalizedColor)) {
      Alert.alert('颜色重复', '该颜色已被其他课程使用，请更换颜色');
      return;
    }

    try {
      const created = await scheduleService.createCourse({
        name,
        teacher: newCourseTeacher.trim() || undefined,
        location: newCourseLocation.trim() || undefined,
        day_of_week: pendingDay,
        start_section: startSection,
        end_section: endSection,
        weeks: repeatWeeks,
        color: normalizedColor,
      });
      setCourses(prev => [...prev, created]);
      closeAddCourseModal();
    } catch (error) {
      console.error('新增课程失败:', error);
      Alert.alert('保存失败', '课程保存失败，请稍后重试');
    }
  }, [
    closeAddCourseModal,
    currentWeek,
    newCourseLocation,
    newCourseName,
    newCourseTeacher,
    newCourseColor,
    pendingDay,
    pendingMergedSection,
    repeatMode,
    startWeekInput,
    usedCourseColors,
    endWeekInput,
    weeks,
  ]);

  // 渲染周选择器
  const renderWeekSelector = () => (
    <View style={styles.weekSelector}>
      <TouchableOpacity
        style={styles.settingsButton}
        onPress={() => setIsSettingsModalVisible(true)}
      >
        <MaterialCommunityIcons name="cog" size={24} color="#FFFFFF" />
      </TouchableOpacity>
      <ScrollView
        ref={weekScrollRef}
        horizontal
        showsHorizontalScrollIndicator={false}
        contentContainerStyle={styles.weekList}
      >
        {weeks.map(week => (
          <TouchableOpacity
            key={week}
            style={[
              styles.weekItem,
              currentWeek === week && styles.weekItemActive,
            ]}
            onPress={() => setCurrentWeek(week)}
          >
            <Text
              style={[
                styles.weekItemText,
                currentWeek === week && styles.weekItemTextActive,
              ]}
            >
              第{week}周
            </Text>
          </TouchableOpacity>
        ))}
      </ScrollView>
    </View>
  );

  // 渲染星期标题行
  const renderHeader = () => {
    const { month: currentMonth, dates: weekDates } = getWeekInfo(currentWeek - 1);
    
    return (
      <View style={styles.header}>
        {/* 左上角月份显示 */}
        <View style={[styles.timeHeader, { width: TIME_COLUMN_WIDTH }]}>
          <Text style={styles.monthText}>{currentMonth}月</Text>
        </View>
        {/* 星期标题 */}
        {VISIBLE_WEEKDAY_NAMES.map((day, index) => (
          <View
            key={day}
            style={[
              styles.dayHeader,
              {
                width: dayColumnWidth,
                backgroundColor: index === activeTodayColumn ? `${colors.primary.main}10` : 'transparent',
              },
            ]}
          >
            <Text
              style={[
                styles.dayHeaderText,
                index === activeTodayColumn && styles.dayHeaderTextActive,
              ]}
            >
              {day}
            </Text>
            <View style={index === activeTodayColumn ? styles.todayDateBadge : undefined}>
              <Text
                style={[
                  styles.dateText,
                  index === activeTodayColumn && styles.dateTextActive,
                ]}
              >
                {weekDates[index]}
              </Text>
            </View>
          </View>
        ))}
      </View>
    );
  };

  // 渲染时间段列
  const renderTimeColumn = () => (
    <View style={[styles.timeColumn, { width: TIME_COLUMN_WIDTH }]}>
      {GROUPED_TIME_SLOTS.map(slot => (
        <View
          key={slot.section}
          style={[
            styles.timeCell,
            { height: SECTION_HEIGHT },
          ]}
        >
          <View style={styles.timeSectionBadge}>
            <Text style={styles.timeSection}>{slot.section}</Text>
          </View>
          <Text style={styles.timeText}>
            {slot.startTime}
            {'\n｜\n'}
            {slot.endTime}
          </Text>
        </View>
      ))}
    </View>
  );

  // 处理长按课程删除
  const handleCourseLongPress = useCallback((course: Course) => {
    const relatedCourses = getRelatedCourses(course);
    const hasMultiple = relatedCourses.length > 1;

    Alert.alert(
      '删除课程',
      `课程：${course.name}`,
      [
        {
          text: '取消',
          style: 'cancel',
        },
        {
          text: '删除本节',
          style: 'destructive',
          onPress: async () => {
            try {
              await scheduleService.deleteCourse(course.id);
              setCourses(prev => prev.filter(c => c.id !== course.id));
              Alert.alert('成功', '已删除本节课程');
            } catch (error) {
              console.error('删除课程失败:', error);
              Alert.alert('删除失败', '请稍后重试');
            }
          },
        },
        ...(hasMultiple
          ? [
              {
                text: '删除全部',
                style: 'destructive' as const,
                onPress: async () => {
                  try {
                    // 删除所有相关课程
                    for (const relatedCourse of relatedCourses) {
                      await scheduleService.deleteCourse(relatedCourse.id);
                    }
                    // 从本地状态中移除
                    const relatedIds = new Set(relatedCourses.map(c => c.id));
                    setCourses(prev => prev.filter(c => !relatedIds.has(c.id)));
                    Alert.alert('成功', `已删除 ${relatedCourses.length} 节课程`);
                  } catch (error) {
                    console.error('批量删除课程失败:', error);
                    Alert.alert('删除失败', '请稍后重试');
                  }
                },
              },
            ]
          : []),
      ],
      { cancelable: true }
    );
  }, [getRelatedCourses]);

  const buildDayDisplayCourses = useCallback((dayCourses: Course[]): CourseDisplayItem[] => {
    const groupedByNameAndSlot = new Map<string, Course[]>();

    dayCourses.forEach(course => {
      // 同名 + 同时间段分组；若出现多条记录，则拆分并排展示
      const key = `${course.name}|${course.dayOfWeek}|${course.startSection}|${course.endSection}`;
      const group = groupedByNameAndSlot.get(key);
      if (group) {
        group.push(course);
      } else {
        groupedByNameAndSlot.set(key, [course]);
      }
    });

    const items: CourseDisplayItem[] = [];
    groupedByNameAndSlot.forEach((groupCourses, groupKey) => {
      groupCourses.forEach((course, index) => {
        items.push({
          key: `${groupKey}|${course.id}|${index}`,
          course,
          locationText: course.location?.trim() ?? '',
          laneIndex: index,
          laneCount: groupCourses.length,
        });
      });
    });

    return items;
  }, []);

  // 渲染课程卡片
  const renderCourseCard = ({ key, course, locationText, laneIndex, laneCount }: CourseDisplayItem) => {
    // 颜色仅按课程名计算，确保同名课在 UI 上颜色一致
    const color = getCourseColor(course.name);
    const startMergedSection = getMergedSectionIndex(course.startSection);
    const endMergedSection = getMergedSectionIndex(course.endSection);
    const duration = endMergedSection - startMergedSection + 1;
    const top = (startMergedSection - 1) * SECTION_HEIGHT;
    const height = duration * SECTION_HEIGHT - 4;
    const laneGap = 2;
    const baseLeft = 2;
    const availableWidth = dayColumnWidth - baseLeft * 2;
    const cardWidth =
      laneCount > 1
        ? (availableWidth - laneGap * (laneCount - 1)) / laneCount
        : availableWidth;
    const left = baseLeft + laneIndex * (cardWidth + laneGap);

    return (
      <TouchableOpacity
        key={key}
        style={[
          styles.courseCard,
          {
            top,
            height,
            backgroundColor: color,
            left,
            width: cardWidth,
          },
        ]}
        onPress={() =>
          navigation.navigate('CourseDetail', {
            course,
            relatedCourses: getRelatedCourses(course),
          })
        }
        onLongPress={() => handleCourseLongPress(course)}
        delayLongPress={500}
        activeOpacity={0.82}
      >
        <Text style={styles.courseName} numberOfLines={3}>
          {formatCourseName(course.name)}
        </Text>
        {locationText ? (
          <Text style={styles.courseLocation}>
            @{locationText}
          </Text>
        ) : null}
      </TouchableOpacity>
    );
  };

  // 渲染单日课程列
  const renderDayColumn = (dayOfWeek: number, columnIndex: number, isLastColumn: boolean) => {
    const currentWeekCourses = getCurrentWeekCourses();
    const dayCourses = currentWeekCourses.filter(
      course => course.dayOfWeek === dayOfWeek
    );
    const displayCourses = buildDayDisplayCourses(dayCourses);

    return (
      <View
        key={dayOfWeek}
        style={[
          styles.dayColumn,
          {
            width: dayColumnWidth,
            borderRightWidth: isLastColumn ? 0 : 1,
            backgroundColor: columnIndex === activeTodayColumn ? `${colors.primary.main}08` : 'transparent',
          },
        ]}
      >
        {/* 课程网格线 */}
        {GROUPED_TIME_SLOTS.map(slot => {
          const occupied = isSlotOccupied(dayOfWeek, slot.section, currentWeekCourses);

          return (
            <TouchableOpacity
              key={slot.section}
              style={[
                styles.gridCell,
                { height: SECTION_HEIGHT },
              ]}
              activeOpacity={1}
              delayLongPress={280}
              onLongPress={() => {
                if (!occupied) {
                  openAddCourseModal(dayOfWeek, slot.section);
                }
              }}
            />
          );
        })}
        {/* 课程卡片 */}
        {displayCourses.map(renderCourseCard)}
      </View>
    );
  };

  // 渲染课程表主体
  const renderScheduleBody = () => (
    <PanGestureHandler
      activeOffsetX={[-8, 8]}
      failOffsetY={[-80, 80]}
      onHandlerStateChange={handleWeekSwipe}
    >
      <View style={styles.scheduleBodyGestureLayer}>
        <ScrollView
          style={styles.scheduleBody}
          showsVerticalScrollIndicator={true}
          contentContainerStyle={styles.scheduleBodyContent}
        >
          {renderTimeColumn()}
          <ScrollView
            horizontal
            showsHorizontalScrollIndicator={false}
          >
            <View style={styles.daysContainer}>
              {VISIBLE_DAY_VALUES.map((dayOfWeek, index) =>
                renderDayColumn(dayOfWeek, index, index === VISIBLE_DAY_VALUES.length - 1)
              )}
            </View>
          </ScrollView>
        </ScrollView>
      </View>
    </PanGestureHandler>
  );

  return (
    <SafeAreaView style={styles.container} edges={['top']}>
      <StatusBar barStyle="light-content" backgroundColor={colors.primary.main} />

      {/* 周选择器 */}
      {renderWeekSelector()}

      {/* 星期标题 */}
      {renderHeader()}

      {/* 课程表主体 */}
      {renderScheduleBody()}

      {/* 设置弹窗 */}
      <Modal
        visible={isSettingsModalVisible}
        transparent
        animationType="fade"
        onRequestClose={() => setIsSettingsModalVisible(false)}
      >
        <View style={styles.addModalMask}>
          <View style={styles.settingsModalCard}>
            <Text style={styles.addModalTitle}>设置</Text>

            <TouchableOpacity
              style={styles.settingsItem}
              onPress={() => {
                setIsSettingsModalVisible(false);
                setIsSyncModalVisible(true);
              }}
            >
              <MaterialCommunityIcons name="cloud-sync" size={22} color={colors.primary.main} />
              <Text style={styles.settingsItemText}>同步教务系统</Text>
              <MaterialCommunityIcons name="chevron-right" size={20} color={colors.text.hint} />
            </TouchableOpacity>

            <TouchableOpacity
              style={styles.settingsCloseBtn}
              onPress={() => setIsSettingsModalVisible(false)}
            >
              <Text style={styles.settingsCloseText}>关闭</Text>
            </TouchableOpacity>
          </View>
        </View>
      </Modal>

      {/* 同步教务系统弹窗 */}
      <Modal
        visible={isSyncModalVisible}
        transparent
        animationType="fade"
        onRequestClose={() => {
          if (!isSyncing) {
            setIsSyncModalVisible(false);
          }
        }}
      >
        <View style={styles.addModalMask}>
          <View style={styles.addModalCard}>
            <Text style={styles.addModalTitle}>同步教务系统</Text>
            <Text style={styles.addModalDesc}>
              输入教务系统账号密码，自动同步课表数据
            </Text>

            <TextInput
              value={syncUsername}
              onChangeText={setSyncUsername}
              placeholder="学号/工号"
              placeholderTextColor={colors.text.hint}
              style={styles.addInput}
              autoCapitalize="none"
              editable={!isSyncing}
            />
            <TextInput
              value={syncPassword}
              onChangeText={setSyncPassword}
              placeholder="密码"
              placeholderTextColor={colors.text.hint}
              style={styles.addInput}
              secureTextEntry
              editable={!isSyncing}
            />

            {isSyncing && (
              <View style={styles.syncingContainer}>
                <ActivityIndicator size="small" color={colors.primary.main} />
                <Text style={styles.syncingText}>正在同步课表数据...</Text>
              </View>
            )}

            <View style={styles.addActions}>
              <TouchableOpacity
                style={[styles.addCancelBtn, isSyncing && styles.addConfirmBtnDisabled]}
                onPress={() => {
                  if (!isSyncing) {
                    setIsSyncModalVisible(false);
                    setSyncUsername('');
                    setSyncPassword('');
                  }
                }}
                activeOpacity={0.8}
                disabled={isSyncing}
              >
                <Text style={styles.addCancelText}>取消</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={[
                  styles.addConfirmBtn,
                  (!syncUsername.trim() || !syncPassword.trim() || isSyncing) && styles.addConfirmBtnDisabled,
                ]}
                onPress={async () => {
                  if (!syncUsername.trim() || !syncPassword.trim()) return;

                  setIsSyncing(true);
                  try {
                    const result = await scheduleService.syncSchedule({
                      username: syncUsername.trim(),
                      password: syncPassword.trim(),
                    });

                    if (result.success) {
                      Alert.alert(
                        '同步成功',
                        `成功同步 ${result.synced_count} 门课程`,
                        [
                          {
                            text: '确定',
                            onPress: () => {
                              setIsSyncModalVisible(false);
                              setSyncUsername('');
                              setSyncPassword('');
                              loadCourses(); // 刷新课表
                            },
                          },
                        ]
                      );
                    } else {
                      Alert.alert(
                        '同步失败',
                        result.error_message || result.message || '请检查账号密码是否正确'
                      );
                    }
                  } catch (error) {
                    console.error('同步课表失败:', error);
                    Alert.alert('同步失败', '网络错误，请稍后重试');
                  } finally {
                    setIsSyncing(false);
                  }
                }}
                activeOpacity={0.8}
                disabled={!syncUsername.trim() || !syncPassword.trim() || isSyncing}
              >
                <Text style={styles.addConfirmText}>
                  {isSyncing ? '同步中...' : '开始同步'}
                </Text>
              </TouchableOpacity>
            </View>
          </View>
        </View>
      </Modal>

      <Modal
        visible={isAddModalVisible}
        transparent
        animationType="fade"
        onRequestClose={closeAddCourseModal}
      >
        <View style={styles.addModalMask}>
          <View style={styles.addModalCard}>
            <Text style={styles.addModalTitle}>添加课程</Text>
            <Text style={styles.addModalDesc}>
              第{currentWeek}周 · {VISIBLE_WEEKDAY_NAMES[pendingDay]} · 第{pendingMergedSection}大节
            </Text>

            <TextInput
              value={newCourseName}
              onChangeText={setNewCourseName}
              placeholder="课程名称（必填）"
              placeholderTextColor={colors.text.hint}
              style={styles.addInput}
            />
            <TextInput
              value={newCourseTeacher}
              onChangeText={setNewCourseTeacher}
              placeholder="教师（选填）"
              placeholderTextColor={colors.text.hint}
              style={styles.addInput}
            />
            <TextInput
              value={newCourseLocation}
              onChangeText={setNewCourseLocation}
              placeholder="地点（选填）"
              placeholderTextColor={colors.text.hint}
              style={styles.addInput}
            />

            <View style={styles.colorSection}>
              <Text style={styles.repeatLabel}>课程颜色（不可重复）</Text>
              <View style={styles.colorPresetRow}>
                {COURSE_COLORS.filter(color => !usedCourseColors.has(normalizeHexColor(color))).map(color => {
                  const normalized = normalizeHexColor(color);
                  const selected = normalizeHexColor(newCourseColor) === normalized;
                  return (
                    <TouchableOpacity
                      key={color}
                      style={[
                        styles.colorPresetItem,
                        { backgroundColor: normalized || color },
                        selected && styles.colorPresetItemActive,
                      ]}
                      onPress={() => setNewCourseColor(normalized)}
                      activeOpacity={0.85}
                    >
                      {selected ? <MaterialCommunityIcons name="check" size={12} color={colors.text.inverse} /> : null}
                    </TouchableOpacity>
                  );
                })}
              </View>
              <TextInput
                value={newCourseColor}
                onChangeText={setNewCourseColor}
                placeholder="#FF6B6B（支持自定义）"
                placeholderTextColor={colors.text.hint}
                style={styles.addInput}
                autoCapitalize="characters"
                maxLength={7}
              />
            </View>

            {repeatMode !== 'single' ? (
              <View style={styles.weekRangeRow}>
                <View style={styles.weekRangeItem}>
                  <Text style={styles.weekRangeLabel}>起始周</Text>
                  <TextInput
                    value={startWeekInput}
                    onChangeText={setStartWeekInput}
                    placeholder={String(currentWeek)}
                    placeholderTextColor={colors.text.hint}
                    style={styles.weekRangeInput}
                    keyboardType="number-pad"
                    maxLength={2}
                  />
                </View>
                <View style={styles.weekRangeItem}>
                  <Text style={styles.weekRangeLabel}>结束周</Text>
                  <TextInput
                    value={endWeekInput}
                    onChangeText={setEndWeekInput}
                    placeholder={String(TOTAL_WEEKS)}
                    placeholderTextColor={colors.text.hint}
                    style={styles.weekRangeInput}
                    keyboardType="number-pad"
                    maxLength={2}
                  />
                </View>
              </View>
            ) : null}

            <View style={styles.repeatSection}>
              <Text style={styles.repeatLabel}>重复</Text>
              <View style={styles.repeatOptions}>
                <TouchableOpacity
                  style={[styles.repeatChip, repeatMode === 'single' && styles.repeatChipActive]}
                  onPress={() => setRepeatMode('single')}
                  activeOpacity={0.8}
                >
                  <Text style={[styles.repeatChipText, repeatMode === 'single' && styles.repeatChipTextActive]}>
                    仅本周
                  </Text>
                </TouchableOpacity>
                <TouchableOpacity
                  style={[styles.repeatChip, repeatMode === 'weekly' && styles.repeatChipActive]}
                  onPress={() => setRepeatMode('weekly')}
                  activeOpacity={0.8}
                >
                  <Text style={[styles.repeatChipText, repeatMode === 'weekly' && styles.repeatChipTextActive]}>
                    每周
                  </Text>
                </TouchableOpacity>
                <TouchableOpacity
                  style={[styles.repeatChip, repeatMode === 'odd' && styles.repeatChipActive]}
                  onPress={() => setRepeatMode('odd')}
                  activeOpacity={0.8}
                >
                  <Text style={[styles.repeatChipText, repeatMode === 'odd' && styles.repeatChipTextActive]}>
                    单周
                  </Text>
                </TouchableOpacity>
                <TouchableOpacity
                  style={[styles.repeatChip, repeatMode === 'even' && styles.repeatChipActive]}
                  onPress={() => setRepeatMode('even')}
                  activeOpacity={0.8}
                >
                  <Text style={[styles.repeatChipText, repeatMode === 'even' && styles.repeatChipTextActive]}>
                    双周
                  </Text>
                </TouchableOpacity>
              </View>
              {repeatMode !== 'single' ? (
                <Text style={styles.repeatHint}>
                  在第{parseWeekInput(startWeekInput, currentWeek)}周到第{parseWeekInput(endWeekInput, TOTAL_WEEKS)}周生效
                </Text>
              ) : null}
            </View>

            <View style={styles.addActions}>
              <TouchableOpacity style={styles.addCancelBtn} onPress={closeAddCourseModal} activeOpacity={0.8}>
                <Text style={styles.addCancelText}>取消</Text>
              </TouchableOpacity>
              <TouchableOpacity
                style={[styles.addConfirmBtn, !newCourseName.trim() && styles.addConfirmBtnDisabled]}
                onPress={confirmAddCourse}
                activeOpacity={0.8}
                disabled={!newCourseName.trim()}
              >
                <Text style={styles.addConfirmText}>保存</Text>
              </TouchableOpacity>
            </View>
          </View>
        </View>
      </Modal>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: colors.background.paper,
  },

  // ── 周选择器 ──────────────────────────────────────────
  weekSelector: {
    height: WEEK_SELECTOR_HEIGHT,
    backgroundColor: colors.primary.main,
    flexDirection: 'row',
    alignItems: 'center',
  },
  settingsButton: {
    width: 40,
    height: 40,
    justifyContent: 'center',
    alignItems: 'center',
    marginLeft: spacing.xs,
  },
  weekList: {
    paddingHorizontal: spacing.sm,
    alignItems: 'center',
  },
  weekItem: {
    paddingHorizontal: spacing.md,
    paddingVertical: 5,
    marginHorizontal: 3,
    borderRadius: borderRadius.full,
  },
  weekItemActive: {
    backgroundColor: 'rgba(255,255,255,0.28)',
  },
  weekItemText: {
    fontSize: fontSizes.sm,
    fontWeight: '500',
    color: 'rgba(255,255,255,0.75)',
    letterSpacing: 0.2,
  },
  weekItemTextActive: {
    color: colors.text.inverse,
    fontWeight: '700',
  },

  // ── 星期标题行 ─────────────────────────────────────────
  header: {
    flexDirection: 'row',
    height: HEADER_HEIGHT,
    backgroundColor: colors.background.paper,
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: colors.divider,
  },
  timeHeader: {
    borderRightWidth: StyleSheet.hairlineWidth,
    borderRightColor: colors.divider,
    alignItems: 'center',
    justifyContent: 'center',
  },
  monthText: {
    fontSize: fontSizes.xs,
    fontWeight: '700',
    color: colors.primary.main,
    letterSpacing: 0.3,
  },
  dayHeader: {
    alignItems: 'center',
    justifyContent: 'center',
    paddingVertical: 3,
  },
  dayHeaderText: {
    fontSize: fontSizes.xs,
    fontWeight: '500',
    color: colors.text.secondary,
    letterSpacing: 0.3,
  },
  dayHeaderTextActive: {
    color: colors.primary.main,
    fontWeight: '700',
  },
  todayDateBadge: {
    width: 22,
    height: 22,
    borderRadius: borderRadius.full,
    backgroundColor: colors.primary.main,
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 2,
  },
  dateText: {
    fontSize: fontSizes.xs,
    color: colors.text.secondary,
    marginTop: 2,
    fontWeight: '400',
  },
  dateTextActive: {
    color: colors.text.inverse,
    fontWeight: '700',
    marginTop: 0,
  },

  // ── 课程表主体 ─────────────────────────────────────────
  scheduleBody: {
    flex: 1,
    backgroundColor: colors.background.default,
    marginBottom: TAB_BAR_HEIGHT,
  },
  scheduleBodyGestureLayer: {
    flex: 1,
  },
  scheduleBodyContent: {
    flexDirection: 'row',
  },

  // ── 时间列 ────────────────────────────────────────────
  timeColumn: {
    backgroundColor: colors.background.paper,
    borderRightWidth: StyleSheet.hairlineWidth,
    borderRightColor: colors.divider,
  },
  timeCell: {
    alignItems: 'center',
    justifyContent: 'center',
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: '#EBEBEB',
    gap: 4,
  },
  timeSectionBadge: {
    width: 22,
    height: 22,
    borderRadius: borderRadius.full,
    backgroundColor: `${colors.primary.main}12`,
    alignItems: 'center',
    justifyContent: 'center',
  },
  timeSection: {
    fontSize: fontSizes.xs,
    fontWeight: '700',
    color: colors.primary.dark,
  },
  timeText: {
    fontSize: 9,
    color: colors.text.hint,
    fontWeight: '400',
    textAlign: 'center',
    lineHeight: 12,
  },

  // ── 日期列容器 ────────────────────────────────────────
  daysContainer: {
    flexDirection: 'row',
  },

  // ── 单日列 ────────────────────────────────────────────
  dayColumn: {
    borderRightWidth: StyleSheet.hairlineWidth,
    borderRightColor: '#EBEBEB',
  },
  gridCell: {
    borderBottomWidth: StyleSheet.hairlineWidth,
    borderBottomColor: '#EBEBEB',
  },

  // ── 课程卡片 ──────────────────────────────────────────
  courseCard: {
    position: 'absolute',
    borderRadius: borderRadius.xl,
    paddingVertical: spacing.xs + 2,
    paddingHorizontal: spacing.xs + 1,
    ...shadows.md,
  },
  courseName: {
    fontSize: 10,
    fontWeight: '700',
    color: colors.text.inverse,
    lineHeight: 13,
    letterSpacing: 0.1,
  },
  courseLocation: {
    fontSize: 9,
    color: 'rgba(255,255,255,0.80)',
    marginTop: 3,
    fontWeight: '500',
    letterSpacing: 0.1,
  },
  courseTeacher: {
    fontSize: 9,
    color: 'rgba(255,255,255,0.75)',
    marginTop: 2,
    fontWeight: '400',
  },

  // ── 添加课程弹窗 ──────────────────────────────────────
  addModalMask: {
    flex: 1,
    backgroundColor: 'rgba(0,0,0,0.40)',
    justifyContent: 'center',
    paddingHorizontal: spacing.lg,
  },
  addModalCard: {
    backgroundColor: colors.background.paper,
    borderRadius: borderRadius['2xl'],
    padding: spacing.xl,
    ...shadows.lg,
  },
  addModalTitle: {
    fontSize: fontSizes.xl,
    fontWeight: '700',
    color: colors.text.primary,
    letterSpacing: 0.3,
  },
  addModalDesc: {
    marginTop: spacing.xs,
    marginBottom: spacing.lg,
    fontSize: fontSizes.sm,
    color: colors.text.secondary,
    fontWeight: '500',
  },
  addInput: {
    height: 46,
    borderWidth: 0,
    borderRadius: borderRadius.lg,
    paddingHorizontal: spacing.md,
    marginBottom: spacing.sm,
    fontSize: fontSizes.md,
    color: colors.text.primary,
    backgroundColor: colors.background.default,
  },
  colorSection: {
    marginBottom: spacing.sm,
  },
  colorPresetRow: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: spacing.xs,
    marginBottom: spacing.sm,
  },
  colorPresetItem: {
    width: 24,
    height: 24,
    borderRadius: borderRadius.full,
    alignItems: 'center',
    justifyContent: 'center',
  },
  colorPresetItemActive: {
    borderWidth: 2,
    borderColor: colors.text.inverse,
  },
  addActions: {
    marginTop: spacing.md,
    flexDirection: 'row',
    justifyContent: 'flex-end',
    gap: spacing.sm,
  },
  addCancelBtn: {
    height: 42,
    paddingHorizontal: spacing.xl,
    borderRadius: borderRadius.full,
    backgroundColor: colors.background.default,
    alignItems: 'center',
    justifyContent: 'center',
  },
  addCancelText: {
    color: colors.text.secondary,
    fontSize: fontSizes.md,
    fontWeight: '600',
  },
  addConfirmBtn: {
    height: 42,
    paddingHorizontal: spacing.xl,
    borderRadius: borderRadius.full,
    backgroundColor: colors.primary.main,
    alignItems: 'center',
    justifyContent: 'center',
  },
  addConfirmBtnDisabled: {
    backgroundColor: colors.primary.light,
    opacity: 0.7,
  },
  addConfirmText: {
    color: colors.text.inverse,
    fontSize: fontSizes.md,
    fontWeight: '700',
    letterSpacing: 0.3,
  },

  // ── 重复选项 ──────────────────────────────────────────
  repeatSection: {
    marginBottom: spacing.sm,
  },
  repeatLabel: {
    fontSize: fontSizes.sm,
    fontWeight: '600',
    color: colors.text.secondary,
    marginBottom: spacing.xs,
    letterSpacing: 0.2,
  },
  repeatOptions: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: spacing.xs,
  },
  repeatChip: {
    paddingHorizontal: spacing.md,
    height: 32,
    borderRadius: borderRadius.full,
    borderWidth: 1.5,
    borderColor: '#E8E8E8',
    backgroundColor: colors.background.paper,
    justifyContent: 'center',
    alignItems: 'center',
  },
  repeatChipActive: {
    borderColor: colors.primary.main,
    backgroundColor: `${colors.primary.main}15`,
  },
  repeatChipText: {
    fontSize: fontSizes.sm,
    color: colors.text.secondary,
    fontWeight: '600',
  },
  repeatChipTextActive: {
    color: colors.primary.main,
    fontWeight: '700',
  },
  repeatHint: {
    marginTop: spacing.xs,
    fontSize: fontSizes.xs,
    color: colors.text.hint,
    fontWeight: '400',
  },

  // ── 周范围输入 ────────────────────────────────────────
  weekRangeRow: {
    flexDirection: 'row',
    gap: spacing.sm,
    marginBottom: spacing.sm,
  },
  weekRangeItem: {
    flex: 1,
  },
  weekRangeLabel: {
    fontSize: fontSizes.sm,
    fontWeight: '600',
    color: colors.text.secondary,
    marginBottom: spacing.xs,
    letterSpacing: 0.2,
  },
  weekRangeInput: {
    height: 42,
    borderWidth: 0,
    borderRadius: borderRadius.lg,
    paddingHorizontal: spacing.md,
    fontSize: fontSizes.md,
    color: colors.text.primary,
    backgroundColor: colors.background.default,
  },

  // ── 设置弹窗 ──────────────────────────────────────────
  settingsModalCard: {
    backgroundColor: colors.background.paper,
    borderRadius: borderRadius['2xl'],
    padding: spacing.xl,
    ...shadows.lg,
    minWidth: 280,
  },
  settingsItem: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingVertical: spacing.md,
    paddingHorizontal: spacing.sm,
    borderRadius: borderRadius.lg,
    backgroundColor: colors.background.default,
    marginTop: spacing.md,
  },
  settingsItemText: {
    flex: 1,
    fontSize: fontSizes.md,
    fontWeight: '600',
    color: colors.text.primary,
    marginLeft: spacing.md,
  },
  settingsCloseBtn: {
    marginTop: spacing.lg,
    height: 46,
    borderRadius: borderRadius.full,
    backgroundColor: colors.background.default,
    alignItems: 'center',
    justifyContent: 'center',
  },
  settingsCloseText: {
    fontSize: fontSizes.md,
    fontWeight: '600',
    color: colors.text.secondary,
  },

  // ── 同步状态 ──────────────────────────────────────────
  syncingContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    marginVertical: spacing.md,
    gap: spacing.sm,
  },
  syncingText: {
    fontSize: fontSizes.sm,
    color: colors.text.secondary,
    fontWeight: '500',
  },
});

export default ScheduleScreen;
