package com.ruoyi.course.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;

import com.ruoyi.course.domain.Clazz;
import com.ruoyi.course.domain.*;
import com.ruoyi.course.domain.dto.ScheduleRequest;
import com.ruoyi.course.domain.dto.ScheduleResult;
import com.ruoyi.course.enums.GradeEnum;
import com.ruoyi.course.mapper.*;
import com.ruoyi.course.service.IClassroomService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 排课核心算法服务
 */
@Slf4j
@Service
public class CourseScheduler {

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private TeacherMapper teacherMapper;

    @Autowired
    private ClassroomMapper classroomMapper;

    @Autowired
    private ClazzMapper clazzMapper;

    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private TimeSlotMapper timeSlotMapper;

    @Autowired
    private ScheduleItemMapper scheduleItemMapper;

    @Autowired
    private StudentScheduleMapper studentScheduleMapper;

    @Autowired
    private ClassScheduleMapper classScheduleMapper;

    @Autowired
    private CourseAssignmentMapper courseAssignmentMapper;

    @Autowired
    private ElectiveSelectionMapper electiveSelectionMapper;

    @Autowired
    private IClassroomService classroomService;

    /**
     * 执行排课 - 完整版本
     */
    @Transactional(rollbackFor = Exception.class)
    public ScheduleResult scheduleCourses(ScheduleRequest request) {
        log.info("开始排课，参数：{}", request);
        long startTime = System.currentTimeMillis();

        ScheduleResult result = new ScheduleResult();
        ScheduleResult.Statistics statistics = new ScheduleResult.Statistics();

        try {
            // 0. 验证班级-教室绑定完整性
            log.info("=== 排课前验证班级-教室绑定 ===");
            Map<String, Object> validationResult = classroomService.validateClassroomAssignments();

            boolean isValid = (boolean) validationResult.get("isValid");
            if (!isValid) {
                @SuppressWarnings("unchecked")
                List<String> errors = (List<String>) validationResult.get("errors");
                result.setSuccess(false);
                result.setMessage("班级-教室绑定验证失败: " + String.join("; ", errors));
                return result;
            }

            int classesWithoutClassroom = (int) validationResult.get("classesWithoutClassroom");
            if (classesWithoutClassroom > 0) {
                log.warn("发现 {} 个班级没有分配教室，尝试自动分配...", classesWithoutClassroom);

                // 自动分配教室
                Map<String, Object> autoAssignResult = classroomService.autoAssignClassrooms(null);
                boolean autoAssignSuccess = (boolean) autoAssignResult.get("success");

                if (!autoAssignSuccess) {
                    result.setSuccess(false);
                    result.setMessage("自动分配教室失败，无法进行排课");
                    return result;
                }

                log.info("自动分配教室成功");
            }

            // 1. 清理旧的排课数据
            clearOldSchedules(request.getSemester());

            // 2. 准备排课数据
            Map<String, Object> preparedData = prepareSchedulingData(request);

            // 3. 排必修课（使用班级固定教室）
            int requiredCoursesScheduled = scheduleRequiredCourses(preparedData, request);
            log.info("必修课排课完成，安排了 {} 节课", requiredCoursesScheduled);

            // 4. 排选修课（走班制，动态分配教室）
            int electiveCoursesScheduled = scheduleElectiveCourses(preparedData, request);
            log.info("选修课排课完成，安排了 {} 个走班班级", electiveCoursesScheduled);

            // 5. 生成班级课表
            generateClassSchedules(preparedData, request);

            // 6. 统计信息
            statistics.setTotalCourses(requiredCoursesScheduled + electiveCoursesScheduled);
            statistics.setScheduledCourses(requiredCoursesScheduled + electiveCoursesScheduled);
            statistics.setTotalTeachers(countTeachers());
            statistics.setTotalClassrooms(countClassrooms());
            statistics.setTotalStudents(countStudents());
            statistics.setScheduleTime((int) (System.currentTimeMillis() - startTime));

            // 7. 计算排课成功率
            int totalRequiredHours = calculateTotalRequiredCourseHours(preparedData, request);
            double requiredSuccessRate = totalRequiredHours > 0 ?
                    (double) requiredCoursesScheduled / totalRequiredHours * 100 : 0;

//            statistics.setRequiredSuccessRate(String.format("%.1f%%", requiredSuccessRate));

            result.setSuccess(true);
            result.setMessage(String.format("排课成功完成。必修课: %d节, 选修课: %d个班级",
                    requiredCoursesScheduled, electiveCoursesScheduled));
            result.setStatistics(statistics);

            log.info("排课成功完成，总耗时：{}ms", System.currentTimeMillis() - startTime);

        } catch (Exception e) {
            log.error("排课失败", e);
            result.setSuccess(false);
            result.setMessage("排课失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 计算必修课总需要课时数
     */
    private int calculateTotalRequiredCourseHours(Map<String, Object> data, ScheduleRequest request) {
        List<Course> requiredCourses = (List<Course>) data.get("requiredCourses");
        List<Clazz> classes = (List<Clazz>) data.get("classes");

        int totalHours = 0;

        for (Clazz clazz : classes) {
            GradeEnum grade = clazz.getGrade(); // 现在是枚举类型
            for (Course course : requiredCourses) {
                if (isCourseForGrade(course, grade)) { // 使用枚举版本
                    int weeklyHours = course.getHoursPerWeek() != null ? course.getHoursPerWeek() : 5;
                    totalHours += weeklyHours;
                }
            }
        }

        return totalHours;
    }


    /**
     * 学生课程冲突问题解决
     */
    private boolean checkStudentTimeConflict(Student student, TimeSlot timeSlot, String semester) {
        LambdaQueryWrapper<StudentSchedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StudentSchedule::getStudentId, student.getId())
                .eq(StudentSchedule::getDayOfWeek, timeSlot.getDayOfWeek())
                .eq(StudentSchedule::getPeriod, timeSlot.getPeriod())
                .eq(StudentSchedule::getSemester, semester);
        return studentScheduleMapper.selectCount(wrapper) == 0;
    }

    /**
     * 教师课时检查
     */
    private boolean canTeacherTakeMoreCourses(Teacher teacher, String semester) {
        // 获取教师本学期已安排课时
        LambdaQueryWrapper<ScheduleItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ScheduleItem::getTeacherId, teacher.getId())
                .eq(ScheduleItem::getSemester, semester)
                .eq(ScheduleItem::getStatus, 1);

        Long scheduledHours = scheduleItemMapper.selectCount(wrapper);

        // 如果没有设置maxHoursPerWeek，默认20课时
        int maxHours = teacher.getMaxHoursPerWeek() != null ?
                teacher.getMaxHoursPerWeek() : 20;

        return scheduledHours < maxHours;
    }




    /**
     * 清理旧的排课数据
     */
    private void clearOldSchedules(String semester) {
        log.info("清理学期 {} 的旧排课数据", semester);

        // 删除排课项
        LambdaUpdateWrapper<ScheduleItem> scheduleItemWrapper = new LambdaUpdateWrapper<>();
        scheduleItemWrapper.eq(ScheduleItem::getSemester, semester);
        scheduleItemMapper.delete(scheduleItemWrapper);

        // 删除学生课表
        LambdaUpdateWrapper<StudentSchedule> studentScheduleWrapper = new LambdaUpdateWrapper<>();
        studentScheduleWrapper.eq(StudentSchedule::getSemester, semester);
        studentScheduleMapper.delete(studentScheduleWrapper);

        // 删除班级课表
        LambdaUpdateWrapper<ClassSchedule> classScheduleWrapper = new LambdaUpdateWrapper<>();
        classScheduleWrapper.eq(ClassSchedule::getSemester, semester);
        classScheduleMapper.delete(classScheduleWrapper);

        // 删除课程分配
        LambdaUpdateWrapper<CourseAssignment> assignmentWrapper = new LambdaUpdateWrapper<>();
        assignmentWrapper.eq(CourseAssignment::getSemester, semester);
        courseAssignmentMapper.delete(assignmentWrapper);
    }

    /**
     * 准备排课数据 - 增强版本（支持班级固定教室）
     */
    private Map<String, Object> prepareSchedulingData(ScheduleRequest request) {
        Map<String, Object> data = new HashMap<>();

        // 1. 获取年级信息 - 改为使用 GradeEnum 列表
        List<GradeEnum> gradeEnums = request.getGrades().stream()
                .map(gradeCode -> GradeEnum.fromCode(gradeCode))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        data.put("gradeEnums", gradeEnums);

        // 2. 获取必修课程（语数外）
        LambdaQueryWrapper<Course> requiredCoursesWrapper = new LambdaQueryWrapper<>();
        requiredCoursesWrapper.eq(Course::getCourseType, "必修")
                .eq(Course::getStatus, 1);
        List<Course> requiredCourses = courseMapper.selectList(requiredCoursesWrapper);
        data.put("requiredCourses", requiredCourses);

        // 3. 获取选修课程
        log.info("获取选修课程，年级列表: {}", gradeEnums);

        // 获取所有选修课，然后在内存中过滤
        LambdaQueryWrapper<Course> electiveCoursesWrapper = new LambdaQueryWrapper<>();
        electiveCoursesWrapper.eq(Course::getCourseType, "选修")
                .eq(Course::getStatus, 1);
        List<Course> allElectiveCourses = courseMapper.selectList(electiveCoursesWrapper);

        // 过滤出适用于指定年级的选修课
        List<Course> electiveCourses = new ArrayList<>();
        for (Course course : allElectiveCourses) {
            boolean applicable = false;
            for (GradeEnum gradeEnum : gradeEnums) {
                if (isCourseForGrade(course, gradeEnum)) {
                    applicable = true;
                    break;
                }
            }

            if (applicable) {
                electiveCourses.add(course);
                log.debug("选修课适用: {} (适用年级: {})",
                        course.getCourseName(), course.getGradeLevel());
            }
        }

        data.put("electiveCourses", electiveCourses);
        log.info("获取到 {} 门选修课程（过滤前 {} 门）",
                electiveCourses.size(), allElectiveCourses.size());

        // 4. 获取时间槽
        List<TimeSlot> allTimeSlots = getTimeSlotsForGrades(gradeEnums, request.getIncludeSeniorSaturday());
        data.put("timeSlots", allTimeSlots);

        // 5. 获取教师信息
        LambdaQueryWrapper<Teacher> teacherWrapper = new LambdaQueryWrapper<>();
        teacherWrapper.eq(Teacher::getStatus, 1);
        List<Teacher> teachers = teacherMapper.selectList(teacherWrapper);
        data.put("teachers", teachers);

        // 6. 获取教室信息
        LambdaQueryWrapper<Classroom> classroomWrapper = new LambdaQueryWrapper<>();
        classroomWrapper.eq(Classroom::getIsAvailable, 1);
        List<Classroom> classrooms = classroomMapper.selectList(classroomWrapper);
        data.put("classrooms", classrooms);

        // 7. 获取班级信息（包含教室绑定）- 使用 GradeEnum 列表
        LambdaQueryWrapper<Clazz> classWrapper = new LambdaQueryWrapper<>();
        classWrapper.in(Clazz::getGrade, gradeEnums)
                .eq(Clazz::getStatus, 1);
        List<Clazz> classes = clazzMapper.selectList(classWrapper);
        data.put("classes", classes);

        // 8. 验证并补充班级教室绑定
        validateAndFixClassroomAssignments(classes, classrooms);
        data.put("classClassroomMap", buildClassClassroomMap(classes, classrooms));

        // 9. 获取学生信息
        List<Student> allStudents = new ArrayList<>();
        for (Clazz clazz : classes) {
            LambdaQueryWrapper<Student> studentWrapper = new LambdaQueryWrapper<>();
            studentWrapper.eq(Student::getClassId, clazz.getId())
                    .eq(Student::getStatus, 1);
            List<Student> classStudents = studentMapper.selectList(studentWrapper);
            allStudents.addAll(classStudents);
        }
        data.put("students", allStudents);

        // 10. 组织时间槽映射 - 使用 GradeEnum 作为键
        Map<GradeEnum, List<TimeSlot>> timeSlotMapByGrade = new HashMap<>();
        for (GradeEnum gradeEnum : gradeEnums) {
            // 先获取该年级所有可能的时间槽
            List<TimeSlot> gradeSlots = allTimeSlots.stream()
                    .filter(slot -> {
                        String gradeLevel = slot.getGradeLevel();
                        return "全部".equals(gradeLevel) ||
                                gradeLevel.contains(String.valueOf(gradeEnum.getCode())) ||
                                isGradeInGradeLevel(gradeEnum, gradeLevel);
                    })
                    .collect(Collectors.toList());

            // 再根据周六限制进行最终过滤
            List<TimeSlot> filteredSlots = filterTimeSlotsForGrade(
                    gradeSlots, gradeEnum, request.getIncludeSeniorSaturday());

            timeSlotMapByGrade.put(gradeEnum, filteredSlots);
        }
        data.put("timeSlotMapByGrade", timeSlotMapByGrade);

        // 11. 构建教师-学科映射
        Map<String, List<Teacher>> teachersBySubject = teachers.stream()
                .collect(Collectors.groupingBy(Teacher::getSubject));
        data.put("teachersBySubject", teachersBySubject);

        // 12. 构建教室-类型映射
        Map<String, List<Classroom>> classroomsByType = classrooms.stream()
                .collect(Collectors.groupingBy(Classroom::getRoomType));
        data.put("classroomsByType", classroomsByType);

        // 13. 构建年级-班级映射
        Map<GradeEnum, List<Clazz>> classesByGradeEnum = classes.stream()
                .collect(Collectors.groupingBy(Clazz::getGrade));
        data.put("classesByGrade", classesByGradeEnum);

        // 14. 初始化占用记录
        data.put("classroomOccupiedSlots", initClassroomOccupiedSlots(classrooms));
        data.put("teacherOccupiedSlots", initTeacherOccupiedSlots(teachers));
        data.put("studentOccupiedSlots", initStudentOccupiedSlots(allStudents));

        log.info("排课数据准备完成:");
        log.info("  班级数: {}", classes.size());
        log.info("  学生数: {}", allStudents.size());
        log.info("  课程数: {}", requiredCourses.size() + electiveCourses.size());
        log.info("  教室数: {}", classrooms.size());
        log.info("  教师数: {}", teachers.size());
        log.info("  时间槽数: {}", allTimeSlots.size());

        return data;
    }

    /**
     * 检查年级是否在年级级别字符串中
     */
    private boolean isGradeInGradeLevel(GradeEnum grade, String gradeLevel) {
        if (gradeLevel == null || gradeLevel.isEmpty()) {
            return false;
        }

        String gradeCode = String.valueOf(grade.getCode());
        String[] codes = gradeLevel.split(",");
        for (String code : codes) {
            if (code.trim().equals(gradeCode)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 过滤年级对应的时间槽 - 使用 GradeEnum
     */
    private List<TimeSlot> filterTimeSlotsForGrade(List<TimeSlot> allTimeSlots, GradeEnum grade, boolean includeSeniorSaturday) {
        return allTimeSlots.stream()
                .filter(slot -> {
                    // 检查是否适用于该年级
                    String gradeLevel = slot.getGradeLevel();
                    boolean gradeMatch = "全部".equals(gradeLevel) ||
                            gradeLevel.contains(String.valueOf(grade.getCode())) ||
                            isGradeInGradeLevel(grade, gradeLevel);

                    if (!gradeMatch) {
                        return false;
                    }

                    // 检查周六限制
                    if (slot.getDayOfWeek() == 6) { // 周六
                        if (grade == GradeEnum.JUNIOR) { // 假设 GradeEnum.SENIOR_THREE 是高三
                            return includeSeniorSaturday; // 高三根据参数决定
                        } else {
                            return false; // 其他年级不含周六
                        }
                    }

                    return true; // 周一至周五
                })
                .collect(Collectors.toList());
    }

    /**
     * 排必修课 - 使用班级固定教室
     */
    private int scheduleRequiredCourses(Map<String, Object> data, ScheduleRequest request) {
        List<Course> requiredCourses = (List<Course>) data.get("requiredCourses");
        List<Clazz> classes = (List<Clazz>) data.get("classes");
        Map<String, List<Teacher>> teachersBySubject = (Map<String, List<Teacher>>) data.get("teachersBySubject");
        Map<GradeEnum, List<TimeSlot>> timeSlotMapByGrade = (Map<GradeEnum, List<TimeSlot>>) data.get("timeSlotMapByGrade");
        Map<Long, Classroom> classClassroomMap = (Map<Long, Classroom>) data.get("classClassroomMap");
        Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots =
                (Map<Long, ClassroomOccupiedSlots>) data.get("classroomOccupiedSlots");
        Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots =
                (Map<Long, Map<Integer, Set<Integer>>>) data.get("teacherOccupiedSlots");
        Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots =
                (Map<Long, Map<Integer, Set<Integer>>>) data.get("studentOccupiedSlots");

        int scheduledCount = 0;
        int conflictCount = 0;

        log.info("开始排必修课...");

        // 按年级处理
        for (GradeEnum gradeEnum : timeSlotMapByGrade.keySet()) {
            List<Clazz> gradeClasses = classes.stream()
                    .filter(c -> gradeEnum.equals(c.getGrade()))
                    .collect(Collectors.toList());

            log.info("为 {} 年级的 {} 个班级排必修课", gradeEnum.getDisplayName(), gradeClasses.size());

            for (Clazz clazz : gradeClasses) {
                // 获取班级固定教室
                Classroom fixedClassroom = classClassroomMap.get(clazz.getId());
                if (fixedClassroom == null) {
                    log.error("班级 {} 没有固定教室，跳过必修课排课", clazz.getClassName());
                    continue;
                }

                // 获取班级学生
                List<Student> classStudents = getClassStudents(clazz);
                if (classStudents.isEmpty()) {
                    log.warn("班级 {} 没有学生，跳过", clazz.getClassName());
                    continue;
                }

                // 获取年级时间槽
                List<TimeSlot> gradeTimeSlots = timeSlotMapByGrade.get(gradeEnum);
                if (gradeTimeSlots == null || gradeTimeSlots.isEmpty()) {
                    log.warn("年级 {} 没有可用时间槽", gradeEnum.getDisplayName());
                    continue;
                }

                // 打乱时间槽顺序，避免模式固定
                List<TimeSlot> shuffledSlots = new ArrayList<>(gradeTimeSlots);
                Collections.shuffle(shuffledSlots);

                // 为班级排必修课程
                for (Course course : requiredCourses) {
                    // 检查课程是否适用于该年级
                    if (!isCourseForGrade(course, gradeEnum)) {
                        continue;
                    }

                    // 获取每周课时数
                    int weeklyHours = course.getHoursPerWeek() != null ? course.getHoursPerWeek() : 5;

                    // 为每节课安排时间
                    for (int hour = 0; hour < weeklyHours; hour++) {
                        boolean scheduled = scheduleRequiredCourseHour(
                                clazz, course, fixedClassroom, classStudents,
                                shuffledSlots, teachersBySubject,
                                classroomOccupiedSlots, teacherOccupiedSlots, studentOccupiedSlots,
                                request.getSemester(), gradeEnum);

                        if (scheduled) {
                            scheduledCount++;
                        } else {
                            conflictCount++;
                        }
                    }
                }
            }
        }

        log.info("必修课排课完成: 成功安排 {} 节课，冲突 {} 节课", scheduledCount, conflictCount);

        // 打印教室使用统计
        logClassroomUsage(classroomOccupiedSlots);

        return scheduledCount;
    }

    /**
     * 安排必修课的一节课
     */
    private boolean scheduleRequiredCourseHour(Clazz clazz, Course course, Classroom fixedClassroom,
                                               List<Student> classStudents, List<TimeSlot> timeSlots,
                                               Map<String, List<Teacher>> teachersBySubject,
                                               Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots,
                                               Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots,
                                               Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots,
                                               String semester, GradeEnum gradeEnum) {

        // 1. 选择教师
        List<Teacher> availableTeachers = teachersBySubject.get(course.getSubject());
        if (availableTeachers == null || availableTeachers.isEmpty()) {
            log.warn("课程 {} 没有可用的教师", course.getCourseName());
            return false;
        }

        Teacher selectedTeacher = selectTeacherForRequiredCourse(availableTeachers, course, semester, teacherOccupiedSlots);
        if (selectedTeacher == null) {
            log.warn("无法为课程 {} 选择教师（课时已满或时间冲突）", course.getCourseName());
            return false;
        }

        // 2. 寻找合适的时间槽
        TimeSlot selectedTimeSlot = findTimeSlotForRequiredCourse(
                timeSlots, fixedClassroom, selectedTeacher, classStudents,
                classroomOccupiedSlots, teacherOccupiedSlots, studentOccupiedSlots);

        if (selectedTimeSlot == null) {
            log.debug("未找到合适的时间槽: 课程={}, 班级={}, 教师={}",
                    course.getCourseName(), clazz.getClassName(), selectedTeacher.getTeacherName());
            return false;
        }

        // 3. 记录占用
        recordOccupiedSlots(fixedClassroom.getId(), selectedTeacher.getId(), classStudents,
                selectedTimeSlot.getDayOfWeek(), selectedTimeSlot.getPeriod(),
                classroomOccupiedSlots, teacherOccupiedSlots, studentOccupiedSlots);

        // 4. 创建排课项
        ScheduleItem scheduleItem = createScheduleItem(course, selectedTeacher, selectedTimeSlot,
                fixedClassroom, clazz, "必修", gradeEnum.getCode(), semester);

        // 5. 为学生创建课表项
        for (Student student : classStudents) {
            createStudentScheduleItem(student, scheduleItem, semester);
        }

        // 6. 更新教师课时统计
        updateTeacherScheduledHours(selectedTeacher, course, semester);

        log.debug("安排必修课: {} - {} ({} {}{}第{}节) @ {}",
                clazz.getClassName(), course.getCourseName(),
                selectedTeacher.getTeacherName(),
                getDayName(selectedTimeSlot.getDayOfWeek()),
                selectedTimeSlot.getSlotType(),
                selectedTimeSlot.getPeriod(),
                fixedClassroom.getRoomName());

        return true;
    }

    /**
     * 为必修课选择教师（考虑时间冲突）
     */
    private Teacher selectTeacherForRequiredCourse(List<Teacher> teachers, Course course,
                                                   String semester,
                                                   Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots) {
        // 先过滤掉课时已满的教师
        List<Teacher> availableTeachers = teachers.stream()
                .filter(teacher -> canTeacherTakeMoreCourses(teacher, semester))
                .collect(Collectors.toList());

        if (availableTeachers.isEmpty()) {
            return null;
        }

        // 选择已安排课时最少的教师
        return availableTeachers.stream()
                .min(Comparator.comparingInt(Teacher::getCourseCount))
                .orElse(availableTeachers.get(0));
    }

    /**
     * 为必修课寻找时间槽
     */
    private TimeSlot findTimeSlotForRequiredCourse(List<TimeSlot> timeSlots, Classroom classroom,
                                                   Teacher teacher, List<Student> students,
                                                   Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots,
                                                   Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots,
                                                   Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots) {

        // 随机打乱，避免模式固定
        List<TimeSlot> shuffled = new ArrayList<>(timeSlots);
        Collections.shuffle(shuffled);

        for (TimeSlot timeSlot : shuffled) {
            int day = timeSlot.getDayOfWeek();
            int period = timeSlot.getPeriod();

            // 检查教室是否被占用
            ClassroomOccupiedSlots classroomSlots = classroomOccupiedSlots.get(classroom.getId());
            if (classroomSlots != null && classroomSlots.isSlotOccupied(day, period)) {
                continue;
            }

            // 检查教师是否被占用
            Map<Integer, Set<Integer>> teacherSlots = teacherOccupiedSlots.get(teacher.getId());
            if (teacherSlots != null && teacherSlots.get(day).contains(period)) {
                continue;
            }

            // 检查学生是否被占用
            boolean studentConflict = false;
            for (Student student : students) {
                Map<Integer, Set<Integer>> studentSlots = studentOccupiedSlots.get(student.getId());
                if (studentSlots != null && studentSlots.get(day).contains(period)) {
                    studentConflict = true;
                    break;
                }
            }

            if (studentConflict) {
                continue;
            }

            // 所有检查通过，返回这个时间槽
            return timeSlot;
        }

        return null;
    }

    /**
     * 记录占用时间槽
     */
    private void recordOccupiedSlots(Long classroomId, Long teacherId, List<Student> students,
                                     int dayOfWeek, int period,
                                     Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots,
                                     Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots,
                                     Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots) {

        // 记录教室占用
        ClassroomOccupiedSlots classroomSlots = classroomOccupiedSlots.get(classroomId);
        if (classroomSlots != null) {
            classroomSlots.addOccupiedSlot(dayOfWeek, period);
        }

        // 记录教师占用
        Map<Integer, Set<Integer>> teacherSlots = teacherOccupiedSlots.get(teacherId);
        if (teacherSlots != null) {
            teacherSlots.get(dayOfWeek).add(period);
        }

        // 记录学生占用
        for (Student student : students) {
            Map<Integer, Set<Integer>> studentSlots = studentOccupiedSlots.get(student.getId());
            if (studentSlots != null) {
                studentSlots.get(dayOfWeek).add(period);
            }
        }
    }

    /**
     * 检查课程是否适用于年级（枚举版本）
     */
    private boolean isCourseForGrade(Course course, GradeEnum grade) {
        if (course == null || grade == null) {
            return false;
        }

        // 获取课程的适用年级字符串（数据库中存储的是逗号分隔的code字符串，如"1,2"）
        String gradeLevel = course.getGradeLevel();
        if (gradeLevel == null || gradeLevel.trim().isEmpty()) {
            return false;
        }

        // 如果是"全部"（数字0）
        if (gradeLevel.contains("0") || "全部".equals(gradeLevel.trim())) {
            return true;
        }

        // 将逗号分隔的code字符串转换为数字列表
        String[] codeStrs = gradeLevel.split(",");
        for (String codeStr : codeStrs) {
            try {
                Integer code = Integer.parseInt(codeStr.trim());
                if (code.equals(grade.getCode())) {
                    return true;
                }
            } catch (NumberFormatException e) {
                log.warn("年级代码格式错误: {}", codeStr);
            }
        }

        return false;
    }

    /**
     * 重载方法：检查课程是否适用于年级（Integer版本）
     */
    private boolean isCourseForGrade(Course course, Integer gradeCode) {
        GradeEnum gradeEnum = GradeEnum.fromCode(gradeCode);
        return gradeEnum != null && isCourseForGrade(course, gradeEnum);
    }



    /**
     * 打印教室使用情况
     */
    private void logClassroomUsage(Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots) {
        log.info("=== 教室使用情况统计 ===");
        for (ClassroomOccupiedSlots slots : classroomOccupiedSlots.values()) {
            if (slots.getOccupiedCount() > 0) {
                log.info("教室 {}: 已安排 {} 节课", slots.classroomName, slots.getOccupiedCount());
            }
        }
    }


    /**
     * 获取班级的所有学生
     */
    private List<Student> getClassStudents(Clazz clazz) {
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Student::getClassId, clazz.getId())
                .eq(Student::getStatus, 1);
        return studentMapper.selectList(wrapper);
    }

    /**
     * 排选修课 - 走班制，重新分班
     */
    private int scheduleElectiveCourses(Map<String, Object> data, ScheduleRequest request) {
        List<Course> electiveCourses = (List<Course>) data.get("electiveCourses");
        List<Student> students = (List<Student>) data.get("students");
        Map<String, List<Teacher>> teachersBySubject = (Map<String, List<Teacher>>) data.get("teachersBySubject");
        Map<String, List<Classroom>> classroomsByType = (Map<String, List<Classroom>>) data.get("classroomsByType");
        Map<GradeEnum, List<TimeSlot>> timeSlotMapByGrade = (Map<GradeEnum, List<TimeSlot>>) data.get("timeSlotMapByGrade");
        Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots =
                (Map<Long, ClassroomOccupiedSlots>) data.get("classroomOccupiedSlots");
        Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots =
                (Map<Long, Map<Integer, Set<Integer>>>) data.get("teacherOccupiedSlots");
        Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots =
                (Map<Long, Map<Integer, Set<Integer>>>) data.get("studentOccupiedSlots");

        int scheduledCount = 0;

        log.info("=== 开始排选修课诊断 ===");
        log.info("选修课程数量: {}", electiveCourses.size());
        log.info("学生总数: {}", students.size());

        if (electiveCourses.isEmpty()) {
            log.error("没有选修课程数据！可能原因：");
            log.error("1. 数据库中没有选修课程记录");
            log.error("2. 选修课程状态不是1（未启用）");
            log.error("3. 选修课程不适用于请求的年级: {}", request.getGrades());
            return 0;
        }

        // 打印每门选修课信息
        for (Course course : electiveCourses) {
            log.info("选修课: ID={}, 名称={}, 学科={}, 适用年级={}, 每周课时={}",
                    course.getId(), course.getCourseName(),
                    course.getSubject(), course.getGradeLevel(),
                    course.getHoursPerWeek());
        }

        // 检查是否有选课记录
        LambdaQueryWrapper<ElectiveSelection> selectionWrapper = new LambdaQueryWrapper<>();
        selectionWrapper.eq(ElectiveSelection::getSemester, request.getSemester())
                .eq(ElectiveSelection::getStatus, 1);
        Long selectionCount = electiveSelectionMapper.selectCount(selectionWrapper);
        log.info("本学期选课记录数: {}", selectionCount);

        if (selectionCount == 0) {
            log.warn("没有选课记录，将使用默认分配");
        }

        // 按选修课程进行排课
        for (Course course : electiveCourses) {
            // 1. 获取选择该课程的学生
            List<Student> courseStudents = getStudentsForElectiveCourse(course, students, request.getSemester());
            if (courseStudents.isEmpty()) {
                log.info("选修课 {} 没有学生选择", course.getCourseName());
                continue;
            }

            log.info("选修课 {}: 有 {} 名学生选择", course.getCourseName(), courseStudents.size());

            // 2. 按年级分组学生
            Map<GradeEnum, List<Student>> studentsByGrade = new HashMap<>();
            for (Student student : courseStudents) {
                // 假设 Student 有 getGrade() 返回 GradeEnum
                GradeEnum grade = student.getGrade();
                studentsByGrade.computeIfAbsent(grade, k -> new ArrayList<>()).add(student);
            }

            // 3. 为每个年级的学生排课
            for (Map.Entry<GradeEnum, List<Student>> entry : studentsByGrade.entrySet()) {
                GradeEnum gradeEnum = entry.getKey();
                List<Student> gradeStudents = entry.getValue();

                if (gradeStudents.isEmpty()) {
                    continue;
                }

                // 4. 生成走班班级（每班最多30人）
                List<List<Student>> electiveClasses = groupStudentsIntoElectiveClasses(gradeStudents, 30);
                log.info("  年级 {}: {} 名学生分成 {} 个走班班级",
                        gradeEnum.getDisplayName(), gradeStudents.size(), electiveClasses.size());

                // 5. 为每个走班班级排课
                for (List<Student> electiveClass : electiveClasses) {
                    boolean scheduled = scheduleElectiveClass(
                            course, electiveClass, gradeEnum, teachersBySubject, classroomsByType,
                            timeSlotMapByGrade.get(gradeEnum), classroomOccupiedSlots, teacherOccupiedSlots,
                            studentOccupiedSlots, request.getSemester());

                    if (scheduled) {
                        scheduledCount++;
                    }
                }
            }
        }

        log.info("选修课排课完成: 安排了 {} 个走班班级", scheduledCount);

        return scheduledCount;
    }

    /**
     * 将学生分组为走班班级
     */
    private List<List<Student>> groupStudentsIntoElectiveClasses(List<Student> students, int maxClassSize) {
        List<List<Student>> classes = new ArrayList<>();

        // 简单分组：按顺序分组
        for (int i = 0; i < students.size(); i += maxClassSize) {
            int end = Math.min(students.size(), i + maxClassSize);
            List<Student> classGroup = new ArrayList<>(students.subList(i, end));
            classes.add(classGroup);
        }

        // 可以优化：按行政班混合，避免一个行政班的学生都在一起
        return classes;
    }

    /**
     * 安排一个走班班级的选修课
     */
    private boolean scheduleElectiveClass(Course course, List<Student> classStudents, GradeEnum gradeEnum,
                                          Map<String, List<Teacher>> teachersBySubject,
                                          Map<String, List<Classroom>> classroomsByType,
                                          List<TimeSlot> timeSlots,
                                          Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots,
                                          Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots,
                                          Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots,
                                          String semester) {

        // 1. 选择教师
        List<Teacher> availableTeachers = teachersBySubject.get(course.getSubject());
        if (availableTeachers == null || availableTeachers.isEmpty()) {
            log.warn("选修课 {} 没有可用的教师", course.getCourseName());
            return false;
        }

        Teacher selectedTeacher = selectTeacherForElectiveCourse(availableTeachers, course, semester, teacherOccupiedSlots);
        if (selectedTeacher == null) {
            log.warn("无法为选修课 {} 选择教师", course.getCourseName());
            return false;
        }

        // 2. 确定需要的教室类型
        String requiredRoomType = getRoomTypeForCourse(course);

        // 3. 寻找合适的时间槽和教室
        TimeSlotClassroomPair pair = findTimeSlotAndClassroomForElectiveClass(
                timeSlots, selectedTeacher, classStudents, requiredRoomType, classroomsByType,
                classroomOccupiedSlots, teacherOccupiedSlots, studentOccupiedSlots);

        if (pair == null) {
            log.warn("未找到合适的时间和教室: 选修课={}, 教师={}",
                    course.getCourseName(), selectedTeacher.getTeacherName());
            return false;
        }

        TimeSlot timeSlot = pair.timeSlot;
        Classroom classroom = pair.classroom;

        // 4. 记录占用
        recordOccupiedSlots(classroom.getId(), selectedTeacher.getId(), classStudents,
                timeSlot.getDayOfWeek(), timeSlot.getPeriod(),
                classroomOccupiedSlots, teacherOccupiedSlots, studentOccupiedSlots);

        // 5. 创建排课项（没有固定班级）
        ScheduleItem scheduleItem = createScheduleItem(course, selectedTeacher, timeSlot,
                classroom, null, "选修", gradeEnum.getCode(), semester);

        // 6. 为每个学生创建课表项
        for (Student student : classStudents) {
            createStudentScheduleItem(student, scheduleItem, semester);
        }

        // 7. 更新教师课时统计
        updateTeacherScheduledHours(selectedTeacher, course, semester);

        log.debug("安排选修课: {} (走班，{}名学生) - {} ({} {}{}第{}节) @ {}",
                course.getCourseName(), classStudents.size(),
                selectedTeacher.getTeacherName(),
                getDayName(timeSlot.getDayOfWeek()),
                timeSlot.getSlotType(),
                timeSlot.getPeriod(),
                classroom.getRoomName());

        return true;
    }

    /**
     * 为选修课选择教师
     */
    private Teacher selectTeacherForElectiveCourse(List<Teacher> teachers, Course course,
                                                   String semester,
                                                   Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots) {
        // 先过滤掉课时已满的教师
        List<Teacher> availableTeachers = teachers.stream()
                .filter(teacher -> canTeacherTakeMoreCourses(teacher, semester))
                .collect(Collectors.toList());

        if (availableTeachers.isEmpty()) {
            return null;
        }

        // 选择已安排课时最少的教师
        return availableTeachers.stream()
                .min(Comparator.comparingInt(Teacher::getCourseCount))
                .orElse(availableTeachers.get(0));
    }

    /**
     * 时间槽和教室对
     */
    private static class TimeSlotClassroomPair {
        TimeSlot timeSlot;
        Classroom classroom;

        TimeSlotClassroomPair(TimeSlot timeSlot, Classroom classroom) {
            this.timeSlot = timeSlot;
            this.classroom = classroom;
        }
    }

    /**
     * 为选修课寻找时间槽和教室
     */
    private TimeSlotClassroomPair findTimeSlotAndClassroomForElectiveClass(
            List<TimeSlot> timeSlots, Teacher teacher, List<Student> students,
            String requiredRoomType, Map<String, List<Classroom>> classroomsByType,
            Map<Long, ClassroomOccupiedSlots> classroomOccupiedSlots,
            Map<Long, Map<Integer, Set<Integer>>> teacherOccupiedSlots,
            Map<Long, Map<Integer, Set<Integer>>> studentOccupiedSlots) {

        // 获取该类型的教室
        List<Classroom> suitableClassrooms = classroomsByType.get(requiredRoomType);
        if (suitableClassrooms == null || suitableClassrooms.isEmpty()) {
            // 如果没有该类型的教室，尝试用普通教室
            suitableClassrooms = classroomsByType.get("普通教室");
            if (suitableClassrooms == null) {
                return null;
            }
        }

        // 过滤掉容量不足的教室
        suitableClassrooms = suitableClassrooms.stream()
                .filter(c -> c.getCapacity() >= students.size())
                .collect(Collectors.toList());

        if (suitableClassrooms.isEmpty()) {
            return null;
        }

        // 打乱时间槽和教室，尝试多种组合
        List<TimeSlot> shuffledTimeSlots = new ArrayList<>(timeSlots);
        Collections.shuffle(shuffledTimeSlots);

        List<Classroom> shuffledClassrooms = new ArrayList<>(suitableClassrooms);
        Collections.shuffle(shuffledClassrooms);

        for (TimeSlot timeSlot : shuffledTimeSlots) {
            int day = timeSlot.getDayOfWeek();
            int period = timeSlot.getPeriod();

            // 检查教师是否被占用
            Map<Integer, Set<Integer>> teacherSlots = teacherOccupiedSlots.get(teacher.getId());
            if (teacherSlots != null && teacherSlots.get(day).contains(period)) {
                continue;
            }

            // 检查学生是否被占用
            boolean studentConflict = false;
            for (Student student : students) {
                Map<Integer, Set<Integer>> studentSlots = studentOccupiedSlots.get(student.getId());
                if (studentSlots != null && studentSlots.get(day).contains(period)) {
                    studentConflict = true;
                    break;
                }
            }

            if (studentConflict) {
                continue;
            }

            // 寻找空闲的教室
            for (Classroom classroom : shuffledClassrooms) {
                ClassroomOccupiedSlots classroomSlots = classroomOccupiedSlots.get(classroom.getId());
                if (classroomSlots != null && !classroomSlots.isSlotOccupied(day, period)) {
                    // 找到合适的组合
                    return new TimeSlotClassroomPair(timeSlot, classroom);
                }
            }
        }

        return null;
    }

    /**
     * 为班级的每个学生创建个人课表项
     */
    private void createStudentSchedulesForClass(Clazz clazz, ScheduleItem scheduleItem, String semester) {
        // 查询班级的所有学生
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Student::getClassId, clazz.getId())
                .eq(Student::getStatus, 1);
        List<Student> students = studentMapper.selectList(wrapper);

        for (Student student : students) {
            createStudentScheduleItem(student, scheduleItem, semester);
        }
    }

    /**
     * 选择课程教师
     */
    private Teacher selectTeacherForCourse(List<Teacher> teachers, Course course) {
        // 简单策略：选择已安排课时最少的教师
        return teachers.stream()
                .min(Comparator.comparingInt(Teacher::getCourseCount))
                .orElse(teachers.get(0));
    }

    /**
     * 为班级查找教室 - 修改为使用班级固定教室
     */
    private Classroom findClassroomForClass(Clazz clazz) {
        if (clazz.getClassroomId() == null) {
            log.error("班级 {} 没有分配固定教室", clazz.getClassName());
            return null;
        }

        Classroom classroom = classroomMapper.selectById(clazz.getClassroomId());
        if (classroom == null) {
            log.error("班级 {} 分配的教室不存在: {}", clazz.getClassName(), clazz.getClassroomId());
        }

        return classroom;
    }


    /**
     * 查找课程时间槽（必修课）
     */
    private TimeSlot findTimeSlotForCourse(List<TimeSlot> timeSlots, Course course, Teacher teacher,
                                           Classroom classroom, String semester) {
        // 找到第一个教师和教室都空闲的时间槽
        return timeSlots.stream()
                .filter(timeSlot -> isTimeSlotAvailable(timeSlot.getId(), teacher.getId(),
                        classroom.getId(), semester))
                .findFirst()
                .orElse(null);
    }

    /**
     * 查找选修课教室
     */
    private Classroom findClassroomForElectiveCourse(Course course, Map<String, List<Classroom>> classroomsByType, int studentCount) {
        // 根据课程类型选择教室
        String roomType = getRoomTypeForCourse(course);
        List<Classroom> suitableClassrooms = classroomsByType.get(roomType);

        if (suitableClassrooms == null || suitableClassrooms.isEmpty()) {
            return null;
        }

        // 选择容量足够且最小的教室
        return suitableClassrooms.stream()
                .filter(classroom -> classroom.getCapacity() >= studentCount)
                .min(Comparator.comparingInt(Classroom::getCapacity))
                .orElse(null);
    }

    /**
     * 获取课程对应的教室类型
     */
    private String getRoomTypeForCourse(Course course) {
        switch (course.getSubject()) {
            case "物理":
            case "化学":
            case "生物":
                return "实验室";
            case "体育":
                return "体育场";
            case "音乐":
            case "美术":
                return "多媒体教室";
            default:
                return "普通教室";
        }
    }

    /**
     * 查找选修课时间槽
     */
    private TimeSlot findTimeSlotForElectiveCourse(List<TimeSlot> timeSlots, Course course, Teacher teacher,
                                                   Classroom classroom, String semester) {
        // 找到第一个教师和教室都空闲的时间槽
        return timeSlots.stream()
                .filter(timeSlot -> isTimeSlotAvailable(timeSlot.getId(), teacher.getId(),
                        classroom.getId(), semester))
                .findFirst()
                .orElse(null);
    }

    /**
     * 获取选择某选修课的学生
     */
    private List<Student> getStudentsForElectiveCourse(Course course, List<Student> allStudents, String semester) {
        // 从学生选课表中查询
        LambdaQueryWrapper<ElectiveSelection> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ElectiveSelection::getCourseId, course.getId())
                .eq(ElectiveSelection::getSemester, semester)
                .eq(ElectiveSelection::getStatus, 1); // 已确认的选课

        List<ElectiveSelection> selections = electiveSelectionMapper.selectList(wrapper);

        if (selections.isEmpty()) {
            // 如果没有选课记录，根据年级分配默认选修课
            return assignDefaultElectivesForCourse(course, allStudents, semester);
        }

        // 根据选课记录获取学生
        Set<Long> studentIds = selections.stream()
                .map(ElectiveSelection::getStudentId)
                .collect(Collectors.toSet());

        return allStudents.stream()
                .filter(student -> studentIds.contains(student.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 为课程分配默认选修学生
     */
    private List<Student> assignDefaultElectivesForCourse(Course course, List<Student> allStudents, String semester) {
        log.info("选修课 {} 没有选课记录，分配默认学生", course.getCourseName());

        // 按年级过滤学生
        List<Student> suitableStudents = new ArrayList<>();
        for (Student student : allStudents) {
            if (isCourseForGrade(course, student.getGrade())) {
                suitableStudents.add(student);
            }
        }

        // 随机选择一部分学生（测试用）
        if (suitableStudents.size() > 30) {
            Collections.shuffle(suitableStudents);
            suitableStudents = suitableStudents.subList(0, 30);
        }

        // 创建选课记录
        for (Student student : suitableStudents) {
            ElectiveSelection selection = new ElectiveSelection();
            selection.setStudentId(student.getId());
            selection.setCourseId(course.getId());
            selection.setPriority(1);
            selection.setStatus(1);
            selection.setSemester(semester);

            try {
                electiveSelectionMapper.insert(selection);
            } catch (Exception e) {
                log.warn("创建选课记录失败: {}", e.getMessage());
            }
        }

        return suitableStudents;
    }



    /**
     * 创建排课项
     */
    private ScheduleItem createScheduleItem(Course course, Teacher teacher, TimeSlot timeSlot,
                                            Classroom classroom, Clazz clazz, String courseType,
                                            Integer gradeCode, String semester) {
        ScheduleItem item = new ScheduleItem();
        item.setCourseId(course.getId());
        item.setTeacherId(teacher.getId());
        item.setTimeSlotId(timeSlot.getId());
        item.setClassroomId(classroom.getId());

        if (clazz != null) {
            item.setClassId(clazz.getId());
        }

        item.setCourseType(courseType);
        item.setGrade(GradeEnum.fromCode(gradeCode)); // 存储年级代码
        item.setDayOfWeek(timeSlot.getDayOfWeek());
        item.setPeriod(timeSlot.getPeriod());
        item.setSemester(semester);
        item.setStatus(1); // 已安排
        item.setRemark(semester + "学期排课");

        scheduleItemMapper.insert(item);
        return item;
    }

    /**
     * 创建学生课表项
     */
    private void createStudentScheduleItem(Student student, ScheduleItem scheduleItem, String semester) {
        // 检查是否已经存在相同的课表项
        LambdaQueryWrapper<StudentSchedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StudentSchedule::getStudentId, student.getId())
                .eq(StudentSchedule::getScheduleItemId, scheduleItem.getId())
                .eq(StudentSchedule::getSemester, semester);

        Long count = studentScheduleMapper.selectCount(wrapper);
        if (count > 0) {
            log.debug("学生 {} 的课表项已存在，跳过创建", student.getId());
            return;
        }

        StudentSchedule studentSchedule = new StudentSchedule();
        studentSchedule.setStudentId(student.getId());
        studentSchedule.setScheduleItemId(scheduleItem.getId());
        studentSchedule.setCourseId(scheduleItem.getCourseId());
        studentSchedule.setTeacherId(scheduleItem.getTeacherId());
        studentSchedule.setClassroomId(scheduleItem.getClassroomId());
        studentSchedule.setDayOfWeek(scheduleItem.getDayOfWeek());
        studentSchedule.setPeriod(scheduleItem.getPeriod());
        studentSchedule.setSemester(semester);
        studentSchedule.setCourseType(scheduleItem.getCourseType()); // 从排课项获取
        studentSchedule.setWeekNumber(1); // 默认从第1周开始

        // 从相关表中获取名称信息
        Course course = courseMapper.selectById(scheduleItem.getCourseId());
        Teacher teacher = teacherMapper.selectById(scheduleItem.getTeacherId());
        Classroom classroom = classroomMapper.selectById(scheduleItem.getClassroomId());

        if (course != null) {
            studentSchedule.setCourseName(course.getCourseName());
        }
        if (teacher != null) {
            studentSchedule.setTeacherName(teacher.getTeacherName());
        }
        if (classroom != null) {
            studentSchedule.setClassroomName(classroom.getRoomName());
        }

        studentScheduleMapper.insert(studentSchedule);
    }

    /**
     * 更新教师已安排课时
     */
    private void updateTeacherScheduledHours(Teacher teacher, Course course, String semester) {
        // 更新教师的已安排课程数
        teacher.setCourseCount(teacher.getCourseCount() + 1);
        teacherMapper.updateById(teacher);

        // 记录课程分配
        CourseAssignment assignment = new CourseAssignment();
        assignment.setTeacherId(teacher.getId());
        assignment.setCourseId(course.getId());
        assignment.setCourseType(course.getCourseType());
        assignment.setHoursPerWeek(course.getHoursPerWeek());
        assignment.setStatus(1);
        assignment.setSemester(semester);

        courseAssignmentMapper.insert(assignment);
    }

    /**
     * 生成班级课表
     */
    private void generateClassSchedules(Map<String, Object> data, ScheduleRequest request) {
        List<Clazz> classes = (List<Clazz>) data.get("classes");

        for (Clazz clazz : classes) {
            // 查询班级的所有排课项（必修课）
            LambdaQueryWrapper<ScheduleItem> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ScheduleItem::getClassId, clazz.getId())
                    .eq(ScheduleItem::getSemester, request.getSemester());
            List<ScheduleItem> classItems = scheduleItemMapper.selectList(wrapper);

            for (ScheduleItem item : classItems) {
                // 检查是否已经存在
                LambdaQueryWrapper<ClassSchedule> classScheduleWrapper = new LambdaQueryWrapper<>();
                classScheduleWrapper.eq(ClassSchedule::getClassId, clazz.getId())
                        .eq(ClassSchedule::getScheduleItemId, item.getId())
                        .eq(ClassSchedule::getSemester, request.getSemester());

                Long count = classScheduleMapper.selectCount(classScheduleWrapper);
                if (count > 0) {
                    continue; // 已经存在，跳过
                }

                ClassSchedule classSchedule = new ClassSchedule();
                classSchedule.setClassId(clazz.getId());
                classSchedule.setScheduleItemId(item.getId());
                classSchedule.setCourseId(item.getCourseId());
                classSchedule.setTeacherId(item.getTeacherId());
                classSchedule.setClassroomId(item.getClassroomId());
                classSchedule.setDayOfWeek(item.getDayOfWeek());
                classSchedule.setPeriod(item.getPeriod());
                classSchedule.setSemester(request.getSemester());
                classSchedule.setIsFixed(1); // 固定课表

                classScheduleMapper.insert(classSchedule);
            }
        }
    }

    /**
     * 统计教师数量
     */
    private int countTeachers() {
        LambdaQueryWrapper<Teacher> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Teacher::getStatus, 1);
        return Math.toIntExact(teacherMapper.selectCount(wrapper));
    }

    /**
     * 统计教室数量
     */
    private int countClassrooms() {
        LambdaQueryWrapper<Classroom> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Classroom::getIsAvailable, 1);
        return Math.toIntExact(classroomMapper.selectCount(wrapper));
    }

    /**
     * 统计学生数量
     */
    private int countStudents() {
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Student::getStatus, 1);
        return Math.toIntExact(studentMapper.selectCount(wrapper));
    }

    /**
     * 检查教师和教室在指定时间是否空闲
     */
    private boolean isTimeSlotAvailable(Long timeSlotId, Long teacherId, Long classroomId, String semester) {
        // 检查教师在该时间是否已有课
        LambdaQueryWrapper<ScheduleItem> teacherWrapper = new LambdaQueryWrapper<>();
        teacherWrapper.eq(ScheduleItem::getTimeSlotId, timeSlotId)
                .eq(ScheduleItem::getTeacherId, teacherId)
                .eq(ScheduleItem::getSemester, semester)
                .eq(ScheduleItem::getStatus, 1);
        Long teacherConflict = scheduleItemMapper.selectCount(teacherWrapper);

        if (teacherConflict > 0) {
            return false;
        }

        // 检查教室在该时间是否已被占用
        LambdaQueryWrapper<ScheduleItem> classroomWrapper = new LambdaQueryWrapper<>();
        classroomWrapper.eq(ScheduleItem::getTimeSlotId, timeSlotId)
                .eq(ScheduleItem::getClassroomId, classroomId)
                .eq(ScheduleItem::getSemester, semester)
                .eq(ScheduleItem::getStatus, 1);
        Long classroomConflict = scheduleItemMapper.selectCount(classroomWrapper);

        return classroomConflict == 0;
    }

    /**
     * 获取学生课表
     */
    public Map<String, Map<Integer, String>> getStudentTimetable(Long studentId, String semester) {
        Map<String, Map<Integer, String>> timetable = new HashMap<>();

        // 初始化每天的课表
        String[] days = {"周一", "周二", "周三", "周四", "周五", "周六"};
        for (String day : days) {
            timetable.put(day, new HashMap<>());
        }

        // 查询学生的课表
        LambdaQueryWrapper<StudentSchedule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StudentSchedule::getStudentId, studentId)
                .eq(StudentSchedule::getSemester, semester);
        List<StudentSchedule> schedules = studentScheduleMapper.selectList(wrapper);

        // 填充课表
        for (StudentSchedule schedule : schedules) {
            String day = getDayName(schedule.getDayOfWeek());
            Integer period = schedule.getPeriod();
            String courseInfo = schedule.getCourseName() + "@" + schedule.getClassroomName();

            timetable.get(day).put(period, courseInfo);
        }

        return timetable;
    }

    /**
     * 获取星期名称
     */
    private String getDayName(Integer dayOfWeek) {
        String[] days = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
        if (dayOfWeek >= 1 && dayOfWeek <= 7) {
            return days[dayOfWeek - 1];
        }
        return "未知";
    }

    /**
     * 初始化时间槽数据
     */
    @Transactional(rollbackFor = Exception.class)
    public void initTimeSlots() {
        log.info("开始初始化时间槽数据");

        // 删除旧数据
        timeSlotMapper.delete(null);

        // 高一高二时间槽（周一到周五，每天5节课）
        initGradeTimeSlots("1,2", 1, 5, 1, 5); // 使用 "1,2" 表示高一高二

        // 高三时间槽（周一到周六，每天5节课）
        initGradeTimeSlots("3", 1, 6, 1, 5); // 使用 "3" 表示高三

        log.info("时间槽数据初始化完成");
    }

    /**
     * 初始化年级时间槽
     */
    private void initGradeTimeSlots(String gradeLevel, int startDay, int endDay, int startPeriod, int endPeriod) {
        for (int day = startDay; day <= endDay; day++) {
            for (int period = startPeriod; period <= endPeriod; period++) {
                TimeSlot timeSlot = createTimeSlot(gradeLevel, day, period, gradeLevel + "_" + day + "_" + period);
                timeSlotMapper.insert(timeSlot);
            }
        }
    }

    /**
     * 创建时间槽
     */
    private TimeSlot createTimeSlot(String gradeLevel, int day, int period, String slotCode) {
        TimeSlot timeSlot = new TimeSlot();

        // 设置基本信息
        timeSlot.setDayOfWeek(day);
        timeSlot.setPeriod(period);

        // 生成时间槽代码
        timeSlot.setSlotCode(slotCode);

        // 设置时间段名称
        String dayName = getDayName(day);
        timeSlot.setSlotName(String.format("%s第%d节", dayName, period));

        // 设置适用年级 - 存储如 "1,2" 或 "3"
        timeSlot.setGradeLevel(gradeLevel);

        // 设置是否可用
        timeSlot.setAvailable(1);

        // 设置时间段类型
        if (period <= 4) {
            timeSlot.setSlotType("上午");
            timeSlot.setStartTime(java.time.LocalTime.of(8 + (period - 1), 0));
            timeSlot.setEndTime(java.time.LocalTime.of(8 + (period - 1), 45));
        } else {
            timeSlot.setSlotType("下午");
            timeSlot.setStartTime(java.time.LocalTime.of(14 + (period - 5), 0));
            timeSlot.setEndTime(java.time.LocalTime.of(14 + (period - 5), 45));
        }

        timeSlot.setRemark("系统初始化");

        return timeSlot;
    }

    // 内部数据结构类
    private static class ClassroomOccupiedSlots {
        private Long classroomId;
        private String classroomName;
        private Map<Integer, Set<Integer>> occupied; // 星期->节次集合

        public ClassroomOccupiedSlots(Long classroomId, String classroomName) {
            this.classroomId = classroomId;
            this.classroomName = classroomName;
            this.occupied = new HashMap<>();
            for (int day = 1; day <= 6; day++) {
                occupied.put(day, new HashSet<>());
            }
        }

        public void addOccupiedSlot(int dayOfWeek, int period) {
            occupied.get(dayOfWeek).add(period);
        }

        public boolean isSlotOccupied(int dayOfWeek, int period) {
            return occupied.get(dayOfWeek).contains(period);
        }

        public int getOccupiedCount() {
            return occupied.values().stream().mapToInt(Set::size).sum();
        }
    }


    /**
     * 验证并修复班级教室绑定
     */
    private void validateAndFixClassroomAssignments(List<Clazz> classes, List<Classroom> classrooms) {
        Map<Long, Classroom> classroomMap = classrooms.stream()
                .collect(Collectors.toMap(Classroom::getId, c -> c));

        int fixedCount = 0;

        for (Clazz clazz : classes) {
            if (clazz.getClassroomId() == null) {
                log.warn("班级 {} 未分配教室，尝试自动分配...", clazz.getClassName());
                // 自动分配教室
                Classroom assignedClassroom = autoAssignClassroomForClass(clazz, classrooms);
                if (assignedClassroom != null) {
                    clazz.setClassroomId(assignedClassroom.getId());
                    clazzMapper.updateById(clazz);
                    fixedCount++;
                    log.info("为班级 {} 分配教室: {}", clazz.getClassName(), assignedClassroom.getRoomName());
                } else {
                    log.error("无法为班级 {} 分配教室", clazz.getClassName());
                }
            } else {
                // 验证教室是否存在且可用
                Classroom classroom = classroomMap.get(clazz.getClassroomId());
                if (classroom == null || classroom.getIsAvailable() != 1) {
                    log.warn("班级 {} 分配的教室无效，重新分配...", clazz.getClassName());
                    Classroom assignedClassroom = autoAssignClassroomForClass(clazz, classrooms);
                    if (assignedClassroom != null) {
                        clazz.setClassroomId(assignedClassroom.getId());
                        clazzMapper.updateById(clazz);
                        fixedCount++;
                        log.info("为班级 {} 重新分配教室: {}", clazz.getClassName(), assignedClassroom.getRoomName());
                    }
                }
            }
        }

        if (fixedCount > 0) {
            log.info("修复了 {} 个班级的教室分配", fixedCount);
        }
    }


    /**
     * 自动为班级分配教室
     */
    private Classroom autoAssignClassroomForClass(Clazz clazz, List<Classroom> classrooms) {
        // 根据班级类型确定需要的教室类型
        String requiredType;
        if ("实验班".equals(clazz.getClassType())) {
            requiredType = "实验室";
        } else if ("特长班".equals(clazz.getClassType())) {
            requiredType = "多媒体教室";
        } else {
            requiredType = "普通教室";
        }

        // 过滤合适的教室
        List<Classroom> suitableClassrooms = classrooms.stream()
                .filter(c -> requiredType.equals(c.getRoomType()))
                .filter(c -> c.getIsAvailable() == 1)
                .filter(c -> c.getCapacity() >= clazz.getStudentCount())
                .sorted(Comparator.comparingInt(Classroom::getCapacity)) // 选容量最接近的
                .collect(Collectors.toList());

        return suitableClassrooms.isEmpty() ? null : suitableClassrooms.get(0);
    }

    /**
     * 构建班级-教室映射
     */
    private Map<Long, Classroom> buildClassClassroomMap(List<Clazz> classes, List<Classroom> classrooms) {
        Map<Long, Classroom> classroomMap = classrooms.stream()
                .collect(Collectors.toMap(Classroom::getId, c -> c));

        Map<Long, Classroom> result = new HashMap<>();
        for (Clazz clazz : classes) {
            if (clazz.getClassroomId() != null) {
                Classroom classroom = classroomMap.get(clazz.getClassroomId());
                if (classroom != null) {
                    result.put(clazz.getId(), classroom);
                    log.debug("班级 {} -> 教室 {}", clazz.getClassName(), classroom.getRoomName());
                }
            }
        }

        return result;
    }

    /**
     * 初始化教室占用记录
     */
    private Map<Long, ClassroomOccupiedSlots> initClassroomOccupiedSlots(List<Classroom> classrooms) {
        Map<Long, ClassroomOccupiedSlots> occupiedSlots = new HashMap<>();
        for (Classroom classroom : classrooms) {
            occupiedSlots.put(classroom.getId(),
                    new ClassroomOccupiedSlots(classroom.getId(), classroom.getRoomName()));
        }
        return occupiedSlots;
    }

    /**
     * 初始化教师占用记录
     */
    private Map<Long, Map<Integer, Set<Integer>>> initTeacherOccupiedSlots(List<Teacher> teachers) {
        Map<Long, Map<Integer, Set<Integer>>> occupiedSlots = new HashMap<>();
        for (Teacher teacher : teachers) {
            Map<Integer, Set<Integer>> teacherSlots = new HashMap<>();
            for (int day = 1; day <= 6; day++) {
                teacherSlots.put(day, new HashSet<>());
            }
            occupiedSlots.put(teacher.getId(), teacherSlots);
        }
        return occupiedSlots;
    }

    /**
     * 初始化学生占用记录
     */
    private Map<Long, Map<Integer, Set<Integer>>> initStudentOccupiedSlots(List<Student> students) {
        Map<Long, Map<Integer, Set<Integer>>> occupiedSlots = new HashMap<>();
        for (Student student : students) {
            Map<Integer, Set<Integer>> studentSlots = new HashMap<>();
            for (int day = 1; day <= 6; day++) {
                studentSlots.put(day, new HashSet<>());
            }
            occupiedSlots.put(student.getId(), studentSlots);
        }
        return occupiedSlots;
    }


    /**
     * 获取时间槽（按年级）- 添加验证
     */
    private List<TimeSlot> getTimeSlotsForGrades(List<GradeEnum> gradeEnums, boolean includeSeniorSaturday) {
        List<TimeSlot> allTimeSlots = new ArrayList<>();

        log.info("获取时间槽，年级: {}, 包含高三周六: {}", gradeEnums, includeSeniorSaturday);

        // 第一步：先获取所有年级通用的时间槽（gradeLevel为"全部"或"0"）
        LambdaQueryWrapper<TimeSlot> commonWrapper = new LambdaQueryWrapper<>();
        commonWrapper.and(wrapper ->
                        wrapper.eq(TimeSlot::getGradeLevel, "全部")
                                .or()
                                .eq(TimeSlot::getGradeLevel, "0")
                )
                .eq(TimeSlot::getAvailable, 1);

        // 根据是否包含高三周六进行过滤
        if (!includeSeniorSaturday) {
            commonWrapper.le(TimeSlot::getDayOfWeek, 5); // 只取周一到周五
        }

        List<TimeSlot> commonSlots = timeSlotMapper.selectList(commonWrapper);
        allTimeSlots.addAll(commonSlots);
        log.info("通用时间槽数量: {}", commonSlots.size());

        // 第二步：获取每个年级特定的时间槽
        for (GradeEnum gradeEnum : gradeEnums) {
            LambdaQueryWrapper<TimeSlot> gradeWrapper = new LambdaQueryWrapper<>();

            // 匹配包含该年级代码的时间槽
            String gradeCode = String.valueOf(gradeEnum.getCode());
            gradeWrapper.and(wrapper -> {
                        // 匹配完全相等
                        wrapper.eq(TimeSlot::getGradeLevel, gradeCode)
                                .or()
                                // 匹配以该年级开头
                                .likeRight(TimeSlot::getGradeLevel, gradeCode + ",")
                                .or()
                                // 匹配以该年级结尾
                                .likeLeft(TimeSlot::getGradeLevel, "," + gradeCode)
                                .or()
                                // 匹配在中间
                                .like(TimeSlot::getGradeLevel, "," + gradeCode + ",");
                    })
                    .eq(TimeSlot::getAvailable, 1);

            // 对于高三且包含周六，不限制天数
            // 对于其他年级或者高三不包含周六，限制为周一到周五
            if (gradeEnum != GradeEnum.JUNIOR || !includeSeniorSaturday) {
                gradeWrapper.le(TimeSlot::getDayOfWeek, 5);
            }

            List<TimeSlot> gradeSlots = timeSlotMapper.selectList(gradeWrapper);
            allTimeSlots.addAll(gradeSlots);
            log.info("年级 {} 特定时间槽数量: {}", gradeEnum.getDisplayName(), gradeSlots.size());
        }

        // 去重（基于时间槽ID）
        Map<Long, TimeSlot> uniqueSlots = new LinkedHashMap<>();
        for (TimeSlot slot : allTimeSlots) {
            uniqueSlots.putIfAbsent(slot.getId(), slot);
        }

        List<TimeSlot> result = new ArrayList<>(uniqueSlots.values());
        log.info("去重后时间槽总数: {}", result.size());

        return result;
    }

    /**
     * 诊断排课问题
     */
    @Transactional(readOnly = true)
    public Map<String, Object> diagnoseSchedulingIssues(ScheduleRequest request) {
        Map<String, Object> diagnosis = new HashMap<>();
        List<String> issues = new ArrayList<>();

        log.info("=== 开始排课问题诊断 ===");

        // 1. 检查选修课程
        LambdaQueryWrapper<Course> electiveWrapper = new LambdaQueryWrapper<>();
        electiveWrapper.eq(Course::getCourseType, "选修")
                .eq(Course::getStatus, 1);

        List<Course> allElectives = courseMapper.selectList(electiveWrapper);
        diagnosis.put("totalElectiveCourses", allElectives.size());

        if (allElectives.isEmpty()) {
            issues.add("数据库中没有选修课程");
        } else {
            // 检查哪些选修课适用于请求的年级
            List<Course> applicableElectives = new ArrayList<>();
            for (Course course : allElectives) {
                for (Integer gradeCode : request.getGrades()) {
                    if (isCourseForGrade(course, gradeCode)) {
                        applicableElectives.add(course);
                        break;
                    }
                }
            }
            diagnosis.put("applicableElectiveCourses", applicableElectives.size());

            if (applicableElectives.isEmpty()) {
                issues.add("没有选修课程适用于年级: " + request.getGrades());
            }
        }

        // 2. 检查选课记录
        LambdaQueryWrapper<ElectiveSelection> selectionWrapper = new LambdaQueryWrapper<>();
        selectionWrapper.eq(ElectiveSelection::getSemester, request.getSemester())
                .eq(ElectiveSelection::getStatus, 1);

        Long selectionCount = electiveSelectionMapper.selectCount(selectionWrapper);
        diagnosis.put("selectionRecordCount", selectionCount);

        // 3. 检查时间槽
        List<GradeEnum> gradeEnums = request.getGrades().stream()
                .map(gradeCode -> GradeEnum.fromCode(gradeCode))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
        List<TimeSlot> timeSlots = getTimeSlotsForGrades(gradeEnums, request.getIncludeSeniorSaturday());
        diagnosis.put("availableTimeSlots", timeSlots.size());

        if (timeSlots.isEmpty()) {
            issues.add("没有可用时间槽");
        }

        // 4. 检查教师
        LambdaQueryWrapper<Teacher> teacherWrapper = new LambdaQueryWrapper<>();
        teacherWrapper.eq(Teacher::getStatus, 1);

        Long teacherCount = teacherMapper.selectCount(teacherWrapper);
        diagnosis.put("availableTeacherCount", teacherCount);

        // 5. 检查教室
        LambdaQueryWrapper<Classroom> classroomWrapper = new LambdaQueryWrapper<>();
        classroomWrapper.eq(Classroom::getIsAvailable, 1);

        Long classroomCount = classroomMapper.selectCount(classroomWrapper);
        diagnosis.put("availableClassroomCount", classroomCount);

        diagnosis.put("issues", issues);
        diagnosis.put("hasIssues", !issues.isEmpty());

        log.info("诊断完成: {}", diagnosis);

        return diagnosis;
    }

}