package com.ruoyi.course.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import com.ruoyi.course.domain.ScheduleItem;
import com.ruoyi.course.domain.TimeSlot;
import com.ruoyi.course.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 时间表管理服务
 * 主要负责时间槽管理、排课冲突检查、时间表优化等功能
 */
@Service
@Slf4j
public class TimeTableManager {

    @Autowired
    private TimeSlotMapper timeSlotMapper;

    @Autowired
    private ScheduleItemMapper scheduleItemMapper;

    @Autowired
    private StudentScheduleMapper studentScheduleMapper;

    @Autowired
    private ClassScheduleMapper classScheduleMapper;

    @Autowired
    private ElectiveSelectionMapper electiveSelectionMapper;

    @Autowired
    private CourseAssignmentMapper courseAssignmentMapper;

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

        try {
            // 按照外键依赖顺序清理数据
            // 1. 先删除最底层的依赖表（学生选课和课程分配）
//            electiveSelectionMapper.delete(null);
//            courseAssignmentMapper.delete(null);
//
//            // 2. 删除依赖排课项的表（学生课表和班级课表）
//            studentScheduleMapper.delete(null);
//            classScheduleMapper.delete(null);
//
//            // 3. 删除排课项（依赖时间槽）
//            scheduleItemMapper.delete(null);
//
//            // 4. 最后删除时间槽
//            timeSlotMapper.delete(null);

            // 只清理时间槽相关数据，不清理业务数据
            scheduleItemMapper.delete(null);
            studentScheduleMapper.delete(null);
            classScheduleMapper.delete(null);

            log.info("旧数据清理完成");

        } catch (Exception e) {
            log.error("清理旧数据时发生错误", e);
            throw new RuntimeException("初始化失败：清理旧数据时发生错误 - " + e.getMessage());
        }

        try {
            // 初始化高一高二时间槽（周一到周五，每天5节课）
            initGradeTimeSlots("高一,高二", 1, 5, 1, 5);

            // 初始化高三时间槽（周一到周六，每天5节课）
            initGradeTimeSlots("高三", 1, 6, 1, 5);

            log.info("时间槽数据初始化完成");
        } catch (Exception e) {
            log.error("初始化时间槽数据时发生错误", e);
            throw new RuntimeException("初始化失败：创建时间槽时发生错误 - " + e.getMessage());
        }
    }

    /**
     * 安全初始化时间槽（不删除排课数据）
     */
    @Transactional(rollbackFor = Exception.class)
    public void safeInitTimeSlots() {
        log.info("开始安全初始化时间槽数据（不删除排课数据）");

        try {
            // 只删除没有被引用的时间槽
            deleteUnusedTimeSlots();

            // 初始化高一高二时间槽（周一到周五，每天5节课）
            safeInitGradeTimeSlots("高一,高二", 1, 5, 1, 5);

            // 初始化高三时间槽（周一到周六，每天5节课）
            safeInitGradeTimeSlots("高三", 1, 6, 1, 5);

            log.info("时间槽数据安全初始化完成");
        } catch (Exception e) {
            log.error("安全初始化时间槽数据时发生错误", e);
            throw new RuntimeException("安全初始化失败：" + e.getMessage());
        }
    }

    /**
     * 删除未被使用的时间槽
     */
    private void deleteUnusedTimeSlots() {
        // 查询所有时间槽
        List<TimeSlot> allSlots = timeSlotMapper.selectList(null);

        // 查询正在被使用的时间槽ID
        LambdaQueryWrapper<ScheduleItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(ScheduleItem::getTimeSlotId).groupBy(ScheduleItem::getTimeSlotId);
        List<ScheduleItem> usedItems = scheduleItemMapper.selectList(wrapper);
        Set<Long> usedSlotIds = usedItems.stream()
                .map(ScheduleItem::getTimeSlotId)
                .collect(Collectors.toSet());

        // 删除未被使用的时间槽
        int deletedCount = 0;
        for (TimeSlot slot : allSlots) {
            if (!usedSlotIds.contains(slot.getId())) {
                timeSlotMapper.deleteById(slot.getId());
                deletedCount++;
            }
        }

        log.info("删除了 {} 个未被使用的时间槽", deletedCount);
    }

    /**
     * 安全初始化年级时间槽（只创建不存在的时间槽）
     */
    private void safeInitGradeTimeSlots(String gradeLevel, int startDay, int endDay, int startPeriod, int endPeriod) {
        String gradeCode = getGradeCode(gradeLevel);

        for (int day = startDay; day <= endDay; day++) {
            for (int period = startPeriod; period <= endPeriod; period++) {
                String slotCode = gradeCode + "_" + day + "_" + period;

                // 检查是否已存在
                LambdaQueryWrapper<TimeSlot> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(TimeSlot::getSlotCode, slotCode);
                TimeSlot existingSlot = timeSlotMapper.selectOne(wrapper);

                if (existingSlot == null) {
                    // 不存在则创建
                    TimeSlot timeSlot = createTimeSlot(gradeLevel, day, period, slotCode);
                    timeSlotMapper.insert(timeSlot);
                }
            }
        }
    }

    /**
     * 初始化年级时间槽
     */
    private void initGradeTimeSlots(String gradeLevel, int startDay, int endDay, int startPeriod, int endPeriod) {
        String gradeCode = getGradeCode(gradeLevel);

        for (int day = startDay; day <= endDay; day++) {
            for (int period = startPeriod; period <= endPeriod; period++) {
                TimeSlot timeSlot = createTimeSlot(gradeLevel, day, period, gradeCode + "_" + 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));

        // 设置适用年级
        timeSlot.setGradeLevel(gradeLevel);

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

        // 设置时间段类型和具体时间
        setTimeForSlot(timeSlot, period);

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

        return timeSlot;
    }

    /**
     * 设置时间槽的具体时间
     */
    private void setTimeForSlot(TimeSlot timeSlot, int period) {
        // 设置时间段类型
        if (period <= 4) {
            timeSlot.setSlotType("上午");
        } else {
            timeSlot.setSlotType("下午");
        }

        // 设置具体时间
        switch (period) {
            case 1: // 第1节: 8:00-8:45
                timeSlot.setStartTime(LocalTime.of(8, 0));
                timeSlot.setEndTime(LocalTime.of(8, 45));
                break;
            case 2: // 第2节: 8:55-9:40
                timeSlot.setStartTime(LocalTime.of(8, 55));
                timeSlot.setEndTime(LocalTime.of(9, 40));
                break;
            case 3: // 第3节: 10:00-10:45
                timeSlot.setStartTime(LocalTime.of(10, 0));
                timeSlot.setEndTime(LocalTime.of(10, 45));
                break;
            case 4: // 第4节: 10:55-11:40
                timeSlot.setStartTime(LocalTime.of(10, 55));
                timeSlot.setEndTime(LocalTime.of(11, 40));
                break;
            case 5: // 第5节: 14:00-14:45
                timeSlot.setStartTime(LocalTime.of(14, 0));
                timeSlot.setEndTime(LocalTime.of(14, 45));
                break;
            default:
                timeSlot.setStartTime(LocalTime.of(8, 0));
                timeSlot.setEndTime(LocalTime.of(8, 45));
        }
    }

    /**
     * 获取年级代码
     */
    private String getGradeCode(String gradeLevel) {
        if (gradeLevel.contains("高一")) return "G1";
        if (gradeLevel.contains("高二")) return "G2";
        if (gradeLevel.contains("高三")) return "G3";
        return "GX";
    }

    /**
     * 获取星期名称
     */
    private String getDayName(int dayOfWeek) {
        String[] days = {"周一", "周二", "周三", "周四", "周五", "周六", "周日"};
        if (dayOfWeek >= 1 && dayOfWeek <= 7) {
            return days[dayOfWeek - 1];
        }
        return "周" + dayOfWeek;
    }
    
    /**
     * 获取年级可用时间槽
     */
    public List<TimeSlot> getAvailableTimeSlots(String grade, boolean includeSaturday) {
        LambdaQueryWrapper<TimeSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(TimeSlot::getGradeLevel, grade)
                        .or()
                        .eq(TimeSlot::getGradeLevel, "全部"))
               .eq(TimeSlot::getAvailable, 1);
        
        if (!includeSaturday) {
            wrapper.le(TimeSlot::getDayOfWeek, 5); // 不含周六
        }
        
        wrapper.orderByAsc(TimeSlot::getDayOfWeek)
               .orderByAsc(TimeSlot::getPeriod);
        
        return timeSlotMapper.selectList(wrapper);
    }
    
    /**
     * 检查时间槽是否可用
     */
    public 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 List<ScheduleItem> getTeacherConflicts(String semester) {
        // 查询同一教师在同一时间有多个排课的
        String sql = "SELECT si1.* FROM schedule_item si1 " +
                     "INNER JOIN schedule_item si2 ON si1.teacher_id = si2.teacher_id " +
                     "AND si1.time_slot_id = si2.time_slot_id " +
                     "AND si1.id != si2.id " +
                     "WHERE si1.semester = '" + semester + "' " +
                     "AND si2.semester = '" + semester + "' " +
                     "GROUP BY si1.id";
        
        // 这里使用MyBatis-Plus的查询，实际可能需要自定义Mapper方法
        return scheduleItemMapper.selectList(new LambdaQueryWrapper<ScheduleItem>()
                .eq(ScheduleItem::getSemester, semester)
                .inSql(ScheduleItem::getId, 
                       "SELECT si1.id FROM schedule_item si1 " +
                       "INNER JOIN schedule_item si2 ON si1.teacher_id = si2.teacher_id " +
                       "AND si1.time_slot_id = si2.time_slot_id " +
                       "AND si1.id != si2.id " +
                       "WHERE si1.semester = '" + semester + "' " +
                       "AND si2.semester = '" + semester + "'"));
    }
    
    /**
     * 获取教室冲突的排课项
     */
    public List<ScheduleItem> getClassroomConflicts(String semester) {
        // 查询同一教室在同一时间有多个排课的
        return scheduleItemMapper.selectList(new LambdaQueryWrapper<ScheduleItem>()
                .eq(ScheduleItem::getSemester, semester)
                .inSql(ScheduleItem::getId, 
                       "SELECT si1.id FROM schedule_item si1 " +
                       "INNER JOIN schedule_item si2 ON si1.classroom_id = si2.classroom_id " +
                       "AND si1.time_slot_id = si2.time_slot_id " +
                       "AND si1.id != si2.id " +
                       "WHERE si1.semester = '" + semester + "' " +
                       "AND si2.semester = '" + semester + "'"));
    }
    
    /**
     * 获取所有时间冲突
     */
    public List<ScheduleItem> getAllConflicts(String semester) {
        List<ScheduleItem> conflicts = new ArrayList<>();
        
        // 获取教师冲突
        List<ScheduleItem> teacherConflicts = getTeacherConflicts(semester);
        if (!teacherConflicts.isEmpty()) {
            conflicts.addAll(teacherConflicts);
        }
        
        // 获取教室冲突
        List<ScheduleItem> classroomConflicts = getClassroomConflicts(semester);
        if (!classroomConflicts.isEmpty()) {
            conflicts.addAll(classroomConflicts);
        }
        
        // 去重
        return conflicts.stream()
                .collect(Collectors.collectingAndThen(
                        Collectors.toCollection(() -> 
                                new TreeSet<>(Comparator.comparing(ScheduleItem::getId))),
                        ArrayList::new));
    }
    
    /**
     * 查找替代时间槽
     */
    public List<TimeSlot> findAlternativeTimeSlots(ScheduleItem scheduleItem) {
        // 获取同一年级的所有时间槽
        LambdaQueryWrapper<TimeSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.and(w -> w.eq(TimeSlot::getGradeLevel, scheduleItem.getGrade())
                        .or()
                        .eq(TimeSlot::getGradeLevel, "全部"))
               .eq(TimeSlot::getAvailable, 1);
        
        List<TimeSlot> allSlots = timeSlotMapper.selectList(wrapper);
        
        // 过滤出当前时间槽
        return allSlots.stream()
                .filter(slot -> !slot.getId().equals(scheduleItem.getTimeSlotId()))
                .filter(slot -> isTimeSlotAvailable(slot.getId(), scheduleItem.getTeacherId(), 
                        scheduleItem.getClassroomId(), scheduleItem.getSemester()))
                .sorted(Comparator.comparing(TimeSlot::getDayOfWeek)
                        .thenComparing(TimeSlot::getPeriod))
                .collect(Collectors.toList());
    }
    
    /**
     * 优化时间表（重新安排冲突的课程）
     */
    public int optimizeTimetable(String semester) {
        int optimizedCount = 0;
        
        // 获取所有冲突
        List<ScheduleItem> conflicts = getAllConflicts(semester);
        
        for (ScheduleItem conflict : conflicts) {
            // 查找可用的替代时间槽
            List<TimeSlot> alternativeSlots = findAlternativeTimeSlots(conflict);
            
            if (!alternativeSlots.isEmpty()) {
                // 重新安排到新的时间槽
                TimeSlot newSlot = alternativeSlots.get(0);
                conflict.setTimeSlotId(newSlot.getId());
                conflict.setDayOfWeek(newSlot.getDayOfWeek());
                conflict.setPeriod(newSlot.getPeriod());
                conflict.setRemark("时间表优化调整");
                
                scheduleItemMapper.updateById(conflict);
                optimizedCount++;
                
                log.info("优化了排课项 {}，从时间槽 {} 调整到 {}", 
                        conflict.getId(), conflict.getTimeSlotId(), newSlot.getId());
            } else {
                log.warn("无法为排课项 {} 找到替代时间槽", conflict.getId());
            }
        }
        
        log.info("时间表优化完成，共优化了 {} 个冲突", optimizedCount);
        return optimizedCount;
    }
    
    /**
     * 获取时间槽使用统计
     */
    public Map<String, Object> getTimeSlotStatistics(String semester) {
        Map<String, Object> statistics = new HashMap<>();
        
        // 获取总时间槽数
        Long totalSlots = timeSlotMapper.selectCount(null);
        statistics.put("totalSlots", totalSlots);
        
        // 获取已使用时间槽数
        LambdaQueryWrapper<ScheduleItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ScheduleItem::getSemester, semester)
               .eq(ScheduleItem::getStatus, 1);
        
        Long usedSlots = scheduleItemMapper.selectCount(wrapper);
        statistics.put("usedSlots", usedSlots);
        
        // 计算使用率
        if (totalSlots > 0) {
            double usageRate = (double) usedSlots / totalSlots * 100;
            statistics.put("usageRate", String.format("%.2f%%", usageRate));
        } else {
            statistics.put("usageRate", "0.00%");
        }
        
        // 按天统计
        Map<Integer, Long> dailyUsage = new HashMap<>();
        for (int day = 1; day <= 6; day++) {
            LambdaQueryWrapper<ScheduleItem> dayWrapper = new LambdaQueryWrapper<>();
            dayWrapper.eq(ScheduleItem::getSemester, semester)
                      .eq(ScheduleItem::getStatus, 1)
                      .eq(ScheduleItem::getDayOfWeek, day);
            
            Long dayCount = scheduleItemMapper.selectCount(dayWrapper);
            dailyUsage.put(day, dayCount);
        }
        statistics.put("dailyUsage", dailyUsage);
        
        return statistics;
    }
    
    /**
     * 导出时间表数据（用于前端展示）
     */
    public List<Map<String, Object>> exportTimetable(String grade, String semester) {
        List<Map<String, Object>> timetable = new ArrayList<>();
        
        // 获取该年级的时间槽
        List<TimeSlot> timeSlots = getAvailableTimeSlots(grade, true);
        
        for (TimeSlot timeSlot : timeSlots) {
            Map<String, Object> slotInfo = new HashMap<>();
            slotInfo.put("day", timeSlot.getDayOfWeek());
            slotInfo.put("period", timeSlot.getPeriod());
            slotInfo.put("slotName", timeSlot.getSlotName());
            slotInfo.put("startTime", timeSlot.getStartTime());
            slotInfo.put("endTime", timeSlot.getEndTime());
            
            // 查询该时间槽的排课项
            LambdaQueryWrapper<ScheduleItem> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(ScheduleItem::getTimeSlotId, timeSlot.getId())
                   .eq(ScheduleItem::getSemester, semester)
                   .eq(ScheduleItem::getStatus, 1);
            
            List<ScheduleItem> items = scheduleItemMapper.selectList(wrapper);
            if (!items.isEmpty()) {
                ScheduleItem item = items.get(0);
                slotInfo.put("courseId", item.getCourseId());
                slotInfo.put("teacherId", item.getTeacherId());
                slotInfo.put("classroomId", item.getClassroomId());
                slotInfo.put("courseType", item.getCourseType());
            }
            
            timetable.add(slotInfo);
        }
        
        return timetable;
    }
    
    /**
     * 批量禁用时间槽（用于节假日）
     */
    public int disableTimeSlots(List<Integer> days, String reason) {
        LambdaQueryWrapper<TimeSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(TimeSlot::getDayOfWeek, days);
        
        List<TimeSlot> slots = timeSlotMapper.selectList(wrapper);
        
        int disabledCount = 0;
        for (TimeSlot slot : slots) {
            slot.setAvailable(0);
            slot.setRemark("禁用原因: " + reason);
            timeSlotMapper.updateById(slot);
            disabledCount++;
        }
        
        log.info("禁用了 {} 个时间槽，原因: {}", disabledCount, reason);
        return disabledCount;
    }
    
    /**
     * 批量启用时间槽
     */
    public int enableTimeSlots(List<Integer> days) {
        LambdaQueryWrapper<TimeSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(TimeSlot::getDayOfWeek, days);
        
        List<TimeSlot> slots = timeSlotMapper.selectList(wrapper);
        
        int enabledCount = 0;
        for (TimeSlot slot : slots) {
            slot.setAvailable(1);
            slot.setRemark("已启用");
            timeSlotMapper.updateById(slot);
            enabledCount++;
        }
        
        log.info("启用了 {} 个时间槽", enabledCount);
        return enabledCount;
    }
    
    /**
     * 获取节假日时间槽列表
     */
    public List<TimeSlot> getHolidaySlots() {
        LambdaQueryWrapper<TimeSlot> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(TimeSlot::getAvailable, 0);
        return timeSlotMapper.selectList(wrapper);
    }
}