package com.xjrsoft.module.courseTable.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteTable;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xjrsoft.common.enums.CourseAdjustTypeEnum;
import com.xjrsoft.common.enums.TimeNumberEnum;
import com.xjrsoft.common.enums.TimePeriodEnum;
import com.xjrsoft.common.enums.WeekEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.utils.excel.ExcelFillCellMergePrevColUtil;
import com.xjrsoft.common.utils.excel.ExcelMergeUtil;
import com.xjrsoft.config.TimetableConfig;
import com.xjrsoft.module.base.entity.BaseClass;
import com.xjrsoft.module.base.entity.BaseSemester;
import com.xjrsoft.module.base.mapper.BaseSemesterMapper;
import com.xjrsoft.module.base.service.IBaseClassService;
import com.xjrsoft.module.base.service.IBaseSemesterService;
import com.xjrsoft.module.courseTable.dto.ClassListDto;
import com.xjrsoft.module.courseTable.dto.CourseTableParse;
import com.xjrsoft.module.courseTable.entity.ClassTime;
import com.xjrsoft.module.courseTable.entity.CourseTable;
import com.xjrsoft.module.courseTable.mapper.ClassTimeMapper;
import com.xjrsoft.module.courseTable.mapper.CourseTableMapper;
import com.xjrsoft.module.courseTable.service.ICourseTableService;
import com.xjrsoft.module.courseTable.vo.ClassListVo;
import com.xjrsoft.module.schedule.dto.CourseTableAdjustDto;
import com.xjrsoft.module.schedule.dto.CourseTableDto;
import com.xjrsoft.module.schedule.dto.ScheduleWeekExportQueryDto;
import com.xjrsoft.module.schedule.entity.WfCourseAdjust;
import com.xjrsoft.module.schedule.mapper.CourseTableBakMapper;
import com.xjrsoft.module.schedule.util.ScheduleUtil;
import com.xjrsoft.module.schedule.vo.CourseDetailVo;
import com.xjrsoft.module.schedule.vo.CourseListVo;
import com.xjrsoft.module.schedule.vo.CourseTableVo;
import com.xjrsoft.module.schedule.vo.ScheduleWeekExportQueryVo;
import com.xjrsoft.module.student.entity.BaseStudentSchoolRoll;
import com.xjrsoft.module.student.service.IBaseStudentSchoolRollService;
import com.xjrsoft.module.teacher.entity.BaseTeacher;
import com.xjrsoft.module.teacher.entity.XjrUser;
import com.xjrsoft.module.teacher.service.ITeacherbaseManagerService;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFTable;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.poi.xwpf.usermodel.XWPFTableRow;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 课表 服务实现类
 * </p>
 *
 * @author baomidou
 * @since 2023-09-02 02:19:56
 */
@Service
@AllArgsConstructor
public class CourseTableServiceImpl extends ServiceImpl<CourseTableMapper, CourseTable> implements ICourseTableService {

    private final CourseTableMapper courseTableMapper;

    private final IBaseClassService baseClassService;

    private final ITeacherbaseManagerService teacherbaseManagerService;

    private final IBaseSemesterService baseSemesterService;

    private final TimetableConfig timetableConfig;

    private final ClassTimeMapper classTimeMapper;
    private final BaseSemesterMapper baseSemesterMapper;
    private final IBaseStudentSchoolRollService baseStudentSchoolRollService;
    private final CourseTableBakMapper courseTableBakMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean wordImport(InputStream inputStream) throws IOException {
        List<CourseTableParse> parses = courseTableWordParses(inputStream);


        String semester = null;
        if (parses.size() > 0) {
            semester = parses.get(0).getSemester();
        }

        BaseSemester baseSemester = baseSemesterService.getOne(Wrappers.<BaseSemester>query().lambda().eq(BaseSemester::getName, semester));
        if (baseSemester == null) {
            throw new MyException(String.format("学期【%s】不存在", semester));
        }

        // 获取班级信息
        List<BaseClass> baseClassList = baseClassService.list();
        Map<String, BaseClass> baseClassMap = baseClassList.stream().collect(Collectors.toMap(BaseClass::getName, a -> a, (k1, k2) -> k1));

        // 获取教师信息
        MPJLambdaWrapper<XjrUser> queryWrapper = new MPJLambdaWrapper<>();
        queryWrapper
                .disableSubLogicDel()
                .innerJoin(BaseTeacher.class, BaseTeacher::getUserId, XjrUser::getId)
                .selectAll(XjrUser.class);
        List<XjrUser> xjrUserList = teacherbaseManagerService.list(queryWrapper);
        Map<String, XjrUser> xjrUsersMap = xjrUserList.stream().collect(Collectors.toMap(XjrUser::getName, a -> a, (k1, k2) -> k1));

        // 清空所有数据
        courseTableMapper.delete(Wrappers.<CourseTable>query().lambda().eq(CourseTable::getBaseSemesterId, baseSemester.getId()));

        List<CourseTable> params = new ArrayList<>();
        for (CourseTableParse item : parses) {
            CourseTable courseTable = BeanUtil.toBean(item, CourseTable.class);
            courseTable.setBaseSemesterId(baseSemester.getId());
            BaseClass baseClass = baseClassMap.get(item.getClassName());
            if (baseClass != null) {
                courseTable.setClassId(baseClass.getId());
            }
            XjrUser xjrUser = xjrUsersMap.get(item.getTeacherName());
            if (xjrUser != null) {
                courseTable.setTeacherId(xjrUser.getId());
            }
            if (item.getWeeksCn() != null) {
                courseTable.setWeeks(WeekEnum.getCode(item.getWeeksCn()));
            }
            params.add(courseTable);
        }
        return this.saveBatch(params);
    }

    @Override
    public List<ClassListVo> classList(ClassListDto dto) {
        LambdaQueryWrapper<CourseTable> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CourseTable::getClassId, dto.getClassId())
                .eq(ObjectUtil.isNotEmpty(dto.getWeeks()), CourseTable::getWeeks, dto.getWeeks());

        List<CourseTable> courseTables = courseTableMapper.selectList(queryWrapper);

        List<ClassListVo> classListVos = BeanUtil.copyToList(courseTables, ClassListVo.class);
        Boolean isCurrentSummer = isCurrentSummer();

        Map<String, ClassTime> classTimeMap = getClassTimeMap();

        // 获取节次时间
        for (int i = 0; i < classListVos.size(); i++) {
            ClassListVo c = classListVos.get(i);
            String key = String.format("%d_%d", c.getTimePeriod(), c.getTimeNumber());
            ClassTime ct = classTimeMap.get(key);
            if (ct != null) {
                if (isCurrentSummer) {
                    c.setStartTime(ct.getSummerStartTime());
                    c.setEndTime(ct.getSummerEndTime());
                } else {
                    c.setStartTime(ct.getWinterStartTime());
                    c.setEndTime(ct.getWinterEndTime());
                }
            }
        }
        return classListVos;
    }

    @Override
    public CourseTableVo getList(CourseTableDto dto) {

        List<ClassTime> classTimes = classTimeMapper.selectList(
                new QueryWrapper<ClassTime>().lambda().orderByAsc(ClassTime::getSummerStartTime)
        );

        CourseTableVo tableVo = new CourseTableVo();
        tableVo.setClassTimeList(classTimes);

        if (dto.getSemesterId() != null) {
            BaseSemester baseSemester = baseSemesterMapper.selectById(dto.getSemesterId());
            tableVo.setSemesterName(baseSemester.getName());
            LocalDateTime now = LocalDateTime.now();
            //计算本周是第几周
            LocalDateTime startDateTime = LocalDateTime.ofInstant(baseSemester.getStartDate().toInstant(), ZoneId.systemDefault());
            LocalDateTime endDateTime = LocalDateTime.ofInstant(baseSemester.getEndDate().toInstant(), ZoneId.systemDefault());
            Duration between = Duration.between(startDateTime, endDateTime);
            long days = between.toDays();
            int weeks = (int) Math.ceil((double) days / 7);
            if (dto.getWeek() == null) {
                for (int i = 0; i < weeks; i++) {
                    LocalDateTime startDate = startDateTime.plusDays(i * 6).withHour(0).withMinute(0).withSecond(0).withNano(0);
                    LocalDateTime endDate = startDateTime.plusDays((i + 1) * 6).withHour(23).withMinute(59).withSecond(59).withNano(9999);
                    if (now.isAfter(startDate) && now.isBefore(endDate)) {
                        tableVo.setWeek("第" + (i + 1) + "周");
                    }
                }
            } else {
                LocalDateTime startDate = startDateTime.plusDays((dto.getWeek() - 1) * 6).withHour(0).withMinute(0).withSecond(0).withNano(0);
                LocalDateTime endDate = startDateTime.plusDays(dto.getWeek() * 6).withHour(23).withMinute(59).withSecond(59).withNano(9999);
                dto.setStartDate(startDate);
                dto.setEndDate(endDate);
                tableVo.setWeek("第" + dto.getWeek() + "周");
            }

        }
        if (!StrUtil.isEmpty(dto.getTeacherName())) {
            List<XjrUser> userList = teacherbaseManagerService.list(
                    new QueryWrapper<XjrUser>().lambda()
                            .like(!StrUtil.isEmpty(dto.getTeacherName()), XjrUser::getName, dto.getTeacherName())
            );
            List<XjrUser> userList2 = teacherbaseManagerService.list(
                    new QueryWrapper<XjrUser>().lambda()
                            .like(!StrUtil.isEmpty(dto.getTeacherName()), XjrUser::getCode, dto.getTeacherName())
            );
            userList.addAll(userList2);
            if (userList != null && !userList.isEmpty()) {
                XjrUser xjrUser = userList.get(0);
                dto.setTeacherId(xjrUser.getId());
                tableVo.setTeacherName(xjrUser.getName());
            }
        }
        if(dto.getStartDate() != null && dto.getEndDate() != null){
            if(dto.getStudentId() == null && dto.getTeacherId() == null && dto.getClassId() == null){
                dto.setTeacherId(StpUtil.getLoginIdAsLong());
            }else{
                List<BaseStudentSchoolRoll> schoolRolls = baseStudentSchoolRollService.list(
                        new QueryWrapper<BaseStudentSchoolRoll>().lambda().eq(BaseStudentSchoolRoll::getUserId, dto.getStudentId())
                );
                if(schoolRolls != null && !schoolRolls.isEmpty()){
                    dto.setCourseType("class");
                    dto.setClassId(schoolRolls.get(0).getClassId());
                }
            }
        }
        List<CourseDetailVo> list = courseTableMapper.getList(dto);
        tableVo.setCourseList(list);
        tableVo.setClassHour(list.size());
        if (dto.getClassId() != null) {
            BaseClass baseClass = baseClassService.getById(dto.getClassId());
            tableVo.setClassName(baseClass.getName());
        }

        return tableVo;
    }

    /**
     * 调课顶课查询
     */
    @Override
    public List<CourseListVo> getAdjustList(String teacherId, String adjustDate, String classId) {
        CourseTableAdjustDto dto = new CourseTableAdjustDto();
        if (adjustDate != null && !"".equals(adjustDate)) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate localDateTime = LocalDate.parse(adjustDate, formatter);
            DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
            dto.setAdjustDate(adjustDate);
            dto.setWeek(dayOfWeek.getValue());
        }
        dto.setClassId(classId);
        dto.setTeacherId(Long.parseLong(teacherId));
        List<CourseListVo> list = courseTableMapper.getAdjustList(dto);
        for (CourseListVo courseListVo : list) {
            if (courseListVo.getTimePeriod() == 1) {
                courseListVo.setTimePeriodCn("上午");
            } else if (courseListVo.getTimePeriod() == 2) {
                courseListVo.setTimePeriodCn("下午");
            } else if (courseListVo.getTimePeriod() == 3) {
                courseListVo.setTimePeriodCn("晚上");
            }
        }

        return list;
    }

    @Override
    public String getPreCheck(String preCheckType, String courseId, String swapCourseId, String swapDate, String subTeacherId) {
        if (preCheckType != null && !"".equals(preCheckType)) {
            if (CourseAdjustTypeEnum.courseExchange.getCode().equals(preCheckType)) {
                CourseTable courseTable = courseTableMapper.selectById(courseId);
                CourseTable swapCourseTable = courseTableMapper.selectById(swapCourseId);
                try {
                    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                    LocalDate localDateTime = LocalDate.parse(swapDate, formatter);
                    JsonObject preCheck = getExtendPreCheck(localDateTime, courseTable, swapCourseTable);
                    if (preCheck.get("code").getAsInt() == -1 && !preCheck.get("msg").isJsonNull()) {
                        return preCheck.get("msg").getAsString();
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }

            } else if (CourseAdjustTypeEnum.courseSubstitute.getCode().equals(preCheckType)) {
                CourseTable courseTable = courseTableMapper.selectById(courseId);
                try {
                    JsonObject jsonObject = substitutePreTestin(subTeacherId, courseTable);
                    if (jsonObject.get("code").getAsInt() == -1 && !jsonObject.get("msg").isJsonNull()) {
                        return jsonObject.get("msg").getAsString();
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return null;
    }

    @Override
    public Boolean adjustCourse(WfCourseAdjust courseAdjust) throws Exception {
        if (CourseAdjustTypeEnum.courseExchange.getCode().equals(courseAdjust.getAdjustType())) {
            //调课，将双方课程的日期（schedule_date）、时段（time_period）、节次（time_number）、周（week）、星期几(1-7)（weeks）、星期中文（weeks_cn）对调
            CourseTable courseTable = courseTableMapper.selectById(courseAdjust.getCourseId());
            CourseTable swapCourseTable = courseTableMapper.selectById(courseAdjust.getExchangeCourseId());

            CourseTable courseTableBak = BeanUtil.toBean(courseTable, CourseTable.class);
            CourseTable swapCourseTableBak = BeanUtil.toBean(swapCourseTable, CourseTable.class);

            courseTable.setScheduleDate(swapCourseTableBak.getScheduleDate());
            courseTable.setTimePeriod(swapCourseTableBak.getTimePeriod());
            courseTable.setTimeNumber(swapCourseTableBak.getTimeNumber());
            courseTable.setWeek(swapCourseTableBak.getWeek());
            courseTable.setWeeks(swapCourseTableBak.getWeeks());
            courseTable.setWeeksCn(swapCourseTableBak.getWeeksCn());
            courseTableMapper.updateById(courseTable);

            swapCourseTable.setScheduleDate(courseTableBak.getScheduleDate());
            swapCourseTable.setTimePeriod(courseTableBak.getTimePeriod());
            swapCourseTable.setTimeNumber(courseTableBak.getTimeNumber());
            swapCourseTable.setWeek(courseTableBak.getWeek());
            swapCourseTable.setWeeks(courseTableBak.getWeeks());
            swapCourseTable.setWeeksCn(courseTableBak.getWeeksCn());
            courseTableMapper.updateById(swapCourseTable);
            //提交调课接口
            sendExchange(courseTableBak, swapCourseTableBak, courseAdjust);

        } else if (CourseAdjustTypeEnum.courseSubstitute.getCode().equals(courseAdjust.getAdjustType())) {
            CourseTable courseTable = courseTableMapper.selectById(courseAdjust.getCourseId());

            courseTable.setTeacherId(courseAdjust.getExchangeTeacherId());
            courseTableMapper.updateById(courseTable);
            //提交顶课接口
            sendSubstitute(courseTable, courseAdjust);
        }
        return Boolean.TRUE;
    }

    @Override
    public ByteArrayOutputStream listScheduleWeekExportQuery(ScheduleWeekExportQueryDto dto) {
        // 创建一个字节输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        // 获取课程表数据
        CourseTableVo courseTableVo = getCourseTableVo(dto);

        // 构建课程安排导出列表
        List<ScheduleWeekExportQueryVo> scheduleWeekExportQueryVoList = buildScheduleWeekExportQueryList(courseTableVo);

        // 将数据写入Excel文件
        writeScheduleWeekExportToExcel(courseTableVo, outputStream, scheduleWeekExportQueryVoList);

        return outputStream;
    }

    private CourseTableVo getCourseTableVo(ScheduleWeekExportQueryDto dto) {
        CourseTableDto courseTableDto = new CourseTableDto();
        BeanUtils.copyProperties(dto, courseTableDto);
        return this.getList(courseTableDto);
    }

    private List<ScheduleWeekExportQueryVo> buildScheduleWeekExportQueryList(CourseTableVo courseTableVo) {
        List<ClassTime> classTimeList = courseTableVo.getClassTimeList();
        List<CourseDetailVo> courseList = courseTableVo.getCourseList();
        List<ScheduleWeekExportQueryVo> scheduleWeekExportQueryVoList = new ArrayList<>();

        if (!courseList.isEmpty()) {
            Map<Integer, Map<Integer, List<CourseDetailVo>>> courseDetailVoMap = buildCourseDetailMap(courseList);
            scheduleWeekExportQueryVoList.addAll(buildScheduleWeekExportQueryVoList(courseDetailVoMap, classTimeList));
        }

        return scheduleWeekExportQueryVoList;
    }

    private Map<Integer, Map<Integer, List<CourseDetailVo>>> buildCourseDetailMap(List<CourseDetailVo> courseList) {
        // 实现构建课程详情Map的逻辑
        Map<Integer, Map<Integer, List<CourseDetailVo>>> courseDetailVoMap = new HashMap<>();

        for (CourseDetailVo courseDetailVo : courseList) {
            int timePeriod = Integer.parseInt(courseDetailVo.getTimePeriod().trim());
            int timeNumber = Integer.parseInt(courseDetailVo.getTimeNumber().trim());

            // 如果时间段不存在，则创建一个新的时间段Map
            courseDetailVoMap.putIfAbsent(timePeriod, new HashMap<>());

            // 获取当前时间段的Map
            Map<Integer, List<CourseDetailVo>> timePeriodMap = courseDetailVoMap.get(timePeriod);

            // 如果时间序号不存在，则创建一个新的课程列表
            timePeriodMap.putIfAbsent(timeNumber, new ArrayList<>());

            // 将课程详情添加到对应的时间段和时间序号中
            timePeriodMap.get(timeNumber).add(courseDetailVo);
        }

        // 返回构建好的课程详情Map
        return courseDetailVoMap;
    }

    private List<ScheduleWeekExportQueryVo> buildScheduleWeekExportQueryVoList(Map<Integer, Map<Integer, List<CourseDetailVo>>> courseDetailVoMap, List<ClassTime> classTimeList) {
        List<ScheduleWeekExportQueryVo> scheduleWeekExportQueryVoList = new ArrayList<>();
        // 实现构建ScheduleWeekExportQueryVo对象列表的逻辑
        for (ClassTime classTime : classTimeList) {
            ScheduleWeekExportQueryVo scheduleWeekExportQueryVo = new ScheduleWeekExportQueryVo();
            scheduleWeekExportQueryVo.setTimePeriod(TimePeriodEnum.getValue(classTime.getTimePeriod()));
            scheduleWeekExportQueryVo.setTimeNumber(TimeNumberEnum.getValue(classTime.getNumber()));

            Map<Integer, List<CourseDetailVo>> timePeriodListMap = courseDetailVoMap.get(classTime.getTimePeriod());
            if (timePeriodListMap != null) {
                List<CourseDetailVo> courseDetailVoList = timePeriodListMap.get(classTime.getNumber());
                if (courseDetailVoList != null) {
                    Map<Integer, CourseDetailVo> courseDetailVoByWeeksMap = courseDetailVoList.stream()
                            .collect(Collectors.toMap(CourseDetailVo::getWeeks, item -> item));

                    for (int i = 1; i <= 7; i++) {
                        CourseDetailVo courseDetailVo = courseDetailVoByWeeksMap.get(i);
                        if (courseDetailVo != null) {
                            String courseInfo = courseDetailVo.getCourseName() + "\n" +
                                    courseDetailVo.getTeacherName() + "\n" +
                                    courseDetailVo.getClassName() + "\n" +
                                    courseDetailVo.getClassroomName() + "\n";
                            switch (i) {
                                case 1:
                                    scheduleWeekExportQueryVo.setMonday(courseInfo);
                                    break;
                                case 2:
                                    scheduleWeekExportQueryVo.setTuesday(courseInfo);
                                    break;
                                case 3:
                                    scheduleWeekExportQueryVo.setWednesday(courseInfo);
                                    break;
                                case 4:
                                    scheduleWeekExportQueryVo.setThursday(courseInfo);
                                    break;
                                case 5:
                                    scheduleWeekExportQueryVo.setFriday(courseInfo);
                                    break;
                                case 6:
                                    scheduleWeekExportQueryVo.setSaturday(courseInfo);
                                    break;
                                case 7:
                                    scheduleWeekExportQueryVo.setSunday(courseInfo);
                                    break;
                            }
                        }
                    }
                }
            }

            scheduleWeekExportQueryVoList.add(scheduleWeekExportQueryVo);
        }
        // 返回构建好的ScheduleWeekExportQueryVo对象列表
        return scheduleWeekExportQueryVoList;
    }

    private void writeScheduleWeekExportToExcel(CourseTableVo courseTableVo, ByteArrayOutputStream outputStream, List<ScheduleWeekExportQueryVo> scheduleWeekExportQueryVoList) {
        // 创建内容样式
        WriteCellStyle contentWriteCellStyle = createContentCellStyle();
        // 创建头部样式
        WriteCellStyle headWriteCellStyle = createHeadCellStyle();
        // 将数据写入Excel文件
        try (ExcelWriter excelWriter = EasyExcel.write(outputStream, ScheduleWeekExportQueryVo.class)
                .registerWriteHandler(new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle))
                .build()) {

            writeSheetHead(courseTableVo, excelWriter);

            writeSheetContent(excelWriter, scheduleWeekExportQueryVoList);

        }
    }

    private void writeSheetContent(ExcelWriter excelWriter, List<ScheduleWeekExportQueryVo> scheduleWeekExportQueryVoList) {
        int mergeRowIndex = 2;
        int[] mergeColumeIndex = {0};
        ExcelMergeUtil excelFillCellMergeStrategy = new ExcelMergeUtil(mergeRowIndex, mergeColumeIndex);

        WriteTable writeSheetContentTable = EasyExcel.writerTable(1).needHead(Boolean.TRUE).automaticMergeHead(Boolean.TRUE).registerWriteHandler(excelFillCellMergeStrategy).build();
        excelWriter.write(scheduleWeekExportQueryVoList, EasyExcel.writerSheet("模板").build(), writeSheetContentTable);
    }

    private void writeSheetHead(CourseTableVo courseTableVo, ExcelWriter excelWriter) {
        List<List<String>> sheetHeadList = new ArrayList<>();
        sheetHeadList.add(Collections.singletonList(courseTableVo.getSemesterName() + " "
                + ((courseTableVo.getTeacherName() != null) ? courseTableVo.getTeacherName() : courseTableVo.getClassName()) + " "
                + courseTableVo.getWeek() + " "
                + "课程表"));

        ExcelFillCellMergePrevColUtil sheetHeadColumn = new ExcelFillCellMergePrevColUtil();
        sheetHeadColumn.add(0, 0, 8);

        WriteTable writeSheetHeadTable = EasyExcel.writerTable(0).needHead(Boolean.TRUE).head(sheetHeadList).registerWriteHandler(sheetHeadColumn).build();
        excelWriter.write(new ArrayList<>(), EasyExcel.writerSheet("模板").needHead(Boolean.FALSE).build(), writeSheetHeadTable);
    }

    private WriteCellStyle createContentCellStyle() {
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        contentWriteCellStyle.setWrapped(true);

        WriteFont contentWriteFont = new WriteFont();
        contentWriteFont.setFontHeightInPoints((short) 12);
        contentWriteFont.setFontName("宋体");
        contentWriteCellStyle.setWriteFont(contentWriteFont);

        contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
        contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
        contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
        contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());

        return contentWriteCellStyle;
    }

    private WriteCellStyle createHeadCellStyle() {
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontName("宋体");
        headWriteFont.setFontHeightInPoints((short) 14);
        headWriteFont.setBold(true);
        headWriteCellStyle.setWriteFont(headWriteFont);

        headWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        headWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
        headWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        headWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
        headWriteCellStyle.setBorderRight(BorderStyle.THIN);
        headWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
        headWriteCellStyle.setBorderTop(BorderStyle.THIN);
        headWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
        headWriteCellStyle.setWrapped(true);
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        headWriteCellStyle.setShrinkToFit(true);

        return headWriteCellStyle;
    }

    /**
     * 提交顶课接口
     *
     * @param courseTable
     * @param courseAdjust
     * @throws Exception
     */
    void sendSubstitute(CourseTable courseTable, WfCourseAdjust courseAdjust) throws Exception {
        String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/Substitute/Submit";
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("timetableId", courseTable.getJianyueId());
        jsonObject.addProperty("isCycles", Boolean.FALSE);
        jsonObject.addProperty("reason", courseAdjust.getReason());
        jsonObject.addProperty("teacherId", courseAdjust.getUserId());
        JsonArray extendIds = new JsonArray();
        extendIds.add(courseTable.getTeacherId());
        jsonObject.add("extendIds", extendIds);

        //获取时间戳
        long timestamp = System.currentTimeMillis();
        //生成签名
        String sign = ScheduleUtil.createSign(timestamp);
        String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
    }

    /**
     * 提交调课
     *
     * @param courseTable
     * @param swapCourseTable
     * @throws Exception
     */
    void sendExchange(CourseTable courseTable, CourseTable swapCourseTable, WfCourseAdjust courseAdjust) throws Exception {
        String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/Submit";
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("timetableId", courseTable.getJianyueId());
        jsonObject.addProperty("isCycles", Boolean.FALSE);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        jsonObject.addProperty("date", swapCourseTable.getScheduleDate().format(formatter));
        jsonObject.addProperty("numberOfDay", swapCourseTable.getTimeNumber());
        jsonObject.addProperty("rescheduleId", swapCourseTable.getJianyueId());
        jsonObject.addProperty("reason", courseAdjust.getReason());
        jsonObject.addProperty("teacherId", courseAdjust.getUserId());

        //获取时间戳
        long timestamp = System.currentTimeMillis();
        //生成签名
        String sign = ScheduleUtil.createSign(timestamp);
        String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
    }


    /**
     * 顶课预检查
     *
     * @param courseTable
     * @return 检查结果
     */
    JsonObject substitutePreTestin(String subTeacherId, CourseTable courseTable) throws Exception {
        JsonParser jsonParser = new JsonParser();
        String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/Substitute/PreTesting";
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("timetableId", courseTable.getJianyueId());
        jsonObject.addProperty("isCycles", Boolean.FALSE);
        JsonArray extendIds = new JsonArray();
        extendIds.add(subTeacherId);
        jsonObject.add("extendIds", extendIds);
        //获取时间戳
        long timestamp = System.currentTimeMillis();
        //生成签名
        String sign = ScheduleUtil.createSign(timestamp);
        String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
        if (StrUtil.isEmpty(result)) {
            return null;
        }

        return jsonParser.parse(result).getAsJsonObject();
    }

    /**
     * 调课预检查
     *
     * @param courseTable     需要调整的课程
     * @param swapCourseTable 对调的课程
     * @return 检查结果
     */
    JsonObject getExtendPreCheck(LocalDate swapDate, CourseTable courseTable, CourseTable swapCourseTable) throws Exception {
        JsonParser jsonParser = new JsonParser();
        String url = ScheduleUtil.apiUrl + "RescheduleApply/Extend/PreTesting";
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("timetableId", courseTable.getJianyueId());
        jsonObject.addProperty("isCycles", Boolean.FALSE);
//        jsonObject.addProperty("startDate", "2024-01-01");
//        jsonObject.addProperty("endDate", "2024-01-31");
//        jsonObject.addProperty("dayOfweek", 5);
        jsonObject.addProperty("numberOfday", swapCourseTable.getTimeNumber());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        jsonObject.addProperty("date", swapDate.format(formatter));
        jsonObject.addProperty("reschduleId", courseTable.getJianyueId());

        //获取时间戳
        long timestamp = System.currentTimeMillis();
        //生成签名
        String sign = ScheduleUtil.createSign(timestamp);
        String result = ScheduleUtil.doPost(url, jsonObject.toString(), sign, timestamp);
        if (StrUtil.isEmpty(result)) {
            return null;
        }

        return jsonParser.parse(result).getAsJsonObject();
    }

    /**
     * 获取节次
     *
     * @return
     */
    private Map<String, ClassTime> getClassTimeMap() {
        List<ClassTime> classTimes = classTimeMapper.selectList(null);

        Map<String, ClassTime> result = new HashMap<>();

        for (ClassTime item : classTimes) {
            String key = String.format("%d_%d", item.getTimePeriod(), item.getNumber());
            result.put(key, item);
        }

        return result;
    }

    /**
     * 当前时间是否在夏季
     *
     * @return
     */
    private Boolean isCurrentSummer() {
        DateTime now = DateUtil.date();
        DateTime summerStart = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getSummerStart()));
        DateTime summerEnd = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getSummerEnd()));
        DateTime winterStart = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getWinterStart()));
        DateTime winterEnd = DateUtil.parse(String.format("%d-%s", now.year(), timetableConfig.getWinterEnd()));

        // 如果开始时间大于结束时间，开始时间增加1年
        if (DateUtil.compare(summerStart, summerEnd) > 0) {
            summerEnd = DateUtil.offset(summerEnd, DateField.DAY_OF_YEAR, 1);
        }
        if (DateUtil.compare(winterStart, winterEnd) > 0) {
            winterEnd = DateUtil.offset(winterEnd, DateField.DAY_OF_YEAR, 1);
        }

        if (DateUtil.compare(summerStart, now) > 0 && DateUtil.compare(summerEnd, now) < 0) {
            return true;
        }
        return false;
    }

    /**
     * 解析word课表
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    private List<CourseTableParse> courseTableWordParses(InputStream inputStream) throws IOException {
        XWPFDocument doc = new XWPFDocument(inputStream);

        List<XWPFParagraph> paras = doc.getParagraphs();
        String semester = null;
        List<String> cNames = new ArrayList<>();
        //获取标题
        for (int i = 0; i < paras.size(); i++) {
            String txt = paras.get(i).getText();
            if (i == 0) {
                semester = txt;
                continue;
            }
            txt = txt.replaceAll("总课程表", "").replace("\n", "").trim();
            if (!txt.equals("") && !txt.equals(semester)) {
                cNames.add(txt);
            }
        }
        List<CourseTableParse> result = new ArrayList<>();
        //获取文档中所有的表格
        List<XWPFTable> tables = doc.getTables();
        int tNum = 0;
        for (XWPFTable table : tables) {
            int rNum = 0;
            String timePeriod = null;
            List<String> weeks = new ArrayList<>();
            List<XWPFTableRow> rows = table.getRows();
            for (XWPFTableRow row : rows) {
                //获取行对应的单元格
                List<XWPFTableCell> cells = row.getTableCells();
                String timeNumber = null;
                for (int i = 0; i < cells.size(); i++) {
                    String cellText = cells.get(i).getText();
                    if (cellText.equals("") || rNum < 1) continue;

                    if (rNum == 1) {
                        weeks.add(cellText);
                        continue;
                    }
                    if (i == 0) {
                        timePeriod = cellText;
                        continue;
                    }
                    if (i == 1) {
                        timeNumber = cellText;
                        continue;
                    }
                    List<XWPFParagraph> cParagraph = cells.get(i).getParagraphs();
                    CourseTableParse item = new CourseTableParse();
                    item.setSemester(semester);
                    item.setTimePeriod(TimePeriodEnum.getCode(timePeriod));
                    item.setTimeNumber(TimeNumberEnum.getCode(timeNumber));
                    String week = weeks.get(Math.max(i - 2, 0));
                    item.setWeeksCn(week);
                    item.setClassName(cNames.get(tNum));
                    for (int j = 0; j < cParagraph.size(); j++) {
                        cellText = cParagraph.get(j).getText().trim();
                        switch (j) {
                            case 0:
                                item.setCourseName(cellText);
                                break;
                            case 1:
                                item.setTeacherName(cellText);
                                break;
                            case 2:
                                item.setSiteName(cellText);
                                break;
                        }
                    }
                    result.add(item);
                }
                rNum++;
            }
            tNum++;
        }
        inputStream.close();
        return result;
    }
}
