package com.ym.mec.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.*;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.constant.CommonConstants;
import com.ym.mec.common.controller.BaseController;
import com.ym.mec.common.entity.ImGroupMember;
import com.ym.mec.common.entity.ImGroupModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.im.ImFeignService;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext;
import com.ym.mec.util.date.DateUtil;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.WeekFields;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class OnlineMusicGroupServiceImpl implements OnlineMusicGroupService {

    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private MusicGroupStudentFeeDao musicGroupStudentFeeDao;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private CourseScheduleService courseScheduleService;
    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private TeacherDefaultMusicGroupSalaryDao teacherDefaultMusicGroupSalaryDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private TeacherFreeTimeDao teacherFreeTimeDao;
    @Autowired
    private PracticeGroupService practiceGroupService;
    @Autowired
    private ImGroupService imGroupService;
    @Autowired
    private ImGroupMemberService imGroupMemberService;
    @Autowired
    private SysMessageService sysMessageService;

    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    @Override
    public Map<String, Object> createOnlineMusicClassGroup(OnlineMusicGroupCourseDto onlineMusicGroupCourseInfo) {
        if(Objects.isNull(onlineMusicGroupCourseInfo.getMusicGroupId())){
            throw new BizException("请指定乐团");
        }
        if(Objects.isNull(onlineMusicGroupCourseInfo.getStudentId())){
            throw new BizException("请指定学员");
        }
        if(Objects.isNull(onlineMusicGroupCourseInfo.getSubjectId())){
            throw new BizException("请指定学员声部");
        }
        if(Objects.isNull(onlineMusicGroupCourseInfo.getTeacherId())){
            throw new BizException("请指定教师");
        }
        if(Objects.isNull(onlineMusicGroupCourseInfo.getCourseCreateStartTime())){
            throw new BizException("请指定首次上课时间");
        }
        MusicGroup musicGroup = musicGroupDao.get(onlineMusicGroupCourseInfo.getMusicGroupId());
        if(Objects.isNull(musicGroupDao)){
            throw new BizException("乐团不存在");
        }
        MusicGroupStudentFee studentFee = musicGroupStudentFeeDao.findByUser(onlineMusicGroupCourseInfo.getStudentId(), musicGroup.getId());
        if(Objects.isNull(studentFee)){
            throw new BizException("学员缴费信息不存在");
        }
        if(studentFee.getRemainNetworkClassTimes()<=0){
            throw new BizException("该学员费用不足");
        }

        SysUser student = studentDao.lockUserReturnInfo(onlineMusicGroupCourseInfo.getStudentId());
        if(Objects.isNull(student)){
            throw new BizException("学员不存在");
        }
        Teacher teacher = teacherDao.get(onlineMusicGroupCourseInfo.getTeacherId());
        if(Objects.isNull(teacher)){
            throw new BizException("教师不存在");
        }
        Subject subject = subjectDao.get(onlineMusicGroupCourseInfo.getSubjectId());
        if(Objects.isNull(subjectDao)){
            throw new BizException("声部不存在");
        }

        onlineMusicGroupCourseInfo.setCourseCount(8);
        onlineMusicGroupCourseInfo.setSingleClassMinutes(25);
        onlineMusicGroupCourseInfo.setTeachMode(TeachModeEnum.ONLINE);
        CourseTimeDto courseTimeDto=new CourseTimeDto();
        LocalDateTime courseStartLocalDate = LocalDateTime.ofInstant(onlineMusicGroupCourseInfo.getCourseCreateStartTime().toInstant(), DateUtil.zoneId);
        courseTimeDto.setDayOfWeek(courseStartLocalDate.getDayOfWeek().getValue());
        courseTimeDto.setStartClassTime(DateUtil.dateToString(onlineMusicGroupCourseInfo.getCourseCreateStartTime(), "HH:mm:ss"));
        List<CourseTimeDto> ts=new ArrayList<>();
        ts.add(courseTimeDto);
        onlineMusicGroupCourseInfo.setCourseTimes(ts);
        List<CourseSchedule> courses = courseScheduleService.createCourses(onlineMusicGroupCourseInfo, true);
        courses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        Date now=new Date();

        //创建班级信息
        ClassGroup classGroup = new ClassGroup();
        classGroup.setSubjectIdList(onlineMusicGroupCourseInfo.getSubjectId().toString());
        classGroup.setExpectStudentNum(1);
        classGroup.setStudentNum(1);
        classGroup.setName(subject.getName()+"•"+student.getUsername());
        classGroup.setTotalClassTimes(courses.size());
        classGroup.setType(ClassGroupTypeEnum.MUSIC_NETWORK);
        classGroup.setDelFlag(0);
        classGroup.setGroupType(GroupType.MUSIC);
        classGroup.setMusicGroupId(musicGroup.getId());
        classGroup.setCreateTime(now);
        classGroup.setUpdateTime(now);
        classGroupDao.insert(classGroup);

        //创建班级老师关联记录
        ClassGroupTeacherMapper classGroupTeacherMapper = new ClassGroupTeacherMapper();
        classGroupTeacherMapper.setMusicGroupId(classGroup.getMusicGroupId());
        classGroupTeacherMapper.setClassGroupId(classGroup.getId());
        classGroupTeacherMapper.setTeacherRole(TeachTypeEnum.BISHOP);
        classGroupTeacherMapper.setUserId(onlineMusicGroupCourseInfo.getTeacherId());
        classGroupTeacherMapper.setGroupType(GroupType.MUSIC);
        classGroupTeacherMapper.setCreateTime(now);
        classGroupTeacherMapper.setUpdateTime(now);
        classGroupTeacherMapperDao.insert(classGroupTeacherMapper);

        //班级学生关联表
        ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
        classGroupStudentMapper.setMusicGroupId(onlineMusicGroupCourseInfo.getMusicGroupId());
        classGroupStudentMapper.setClassGroupId(classGroup.getId());
        classGroupStudentMapper.setUserId(onlineMusicGroupCourseInfo.getStudentId());
        classGroupStudentMapper.setCreateTime(now);
        classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
        classGroupStudentMapper.setGroupType(GroupType.MUSIC);
        classGroupStudentMapperDao.insert(classGroupStudentMapper);

        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = new ArrayList<>();
        List<CourseScheduleStudentPayment> courseScheduleStudentPayments = new ArrayList<>();
        List<TeacherAttendance> teacherAttendances = new ArrayList<>();

        for (CourseSchedule courseSchedule : courses) {
            //课表
            courseSchedule.setMusicGroupId(onlineMusicGroupCourseInfo.getMusicGroupId());
            courseSchedule.setClassGroupId(classGroup.getId());
            courseSchedule.setName(classGroup.getName());
            courseSchedule.setStatus(CourseStatusEnum.NOT_START);
            courseSchedule.setTeacherId(onlineMusicGroupCourseInfo.getTeacherId());
            courseSchedule.setActualTeacherId(onlineMusicGroupCourseInfo.getTeacherId());
            courseSchedule.setCreateTime(now);
            courseSchedule.setUpdateTime(now);
            courseSchedule.setTeachMode(TeachModeEnum.ONLINE);
            courseSchedule.setType(CourseSchedule.CourseScheduleType.MUSIC_NETWORK);
            courseSchedule.setGroupType(GroupType.MUSIC);
            courseSchedule.setIsLock(0);
            courseSchedule.setOrganId(student.getOrganId());
        }
        courseScheduleDao.batchAddCourseSchedules(courses);
        TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalary = teacherDefaultMusicGroupSalaryDao.findByTeacherAndCourseType(onlineMusicGroupCourseInfo.getTeacherId(), CourseSchedule.CourseScheduleType.MUSIC_NETWORK.getCode());
        if(Objects.isNull(teacherDefaultMusicGroupSalary)){
            throw new BizException("请设置教师课酬");
        }
        BigDecimal teacherDefaultSalary = JSON.parseObject(teacherDefaultMusicGroupSalary.getSalaryRuleJson()).getBigDecimal("1");
        BigDecimal studentSingleCourseCost=BigDecimal.ZERO;
        for (CourseSchedule courseSchedule : courses) {
            //课程与老师薪水表
            CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
            courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
            courseScheduleTeacherSalary.setGroupType(GroupType.MUSIC);
            courseScheduleTeacherSalary.setMusicGroupId(musicGroup.getId());
            courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
            courseScheduleTeacherSalary.setUserId(onlineMusicGroupCourseInfo.getTeacherId());
            courseScheduleTeacherSalary.setExpectSalary(teacherDefaultSalary);
            courseScheduleTeacherSalary.setCreateTime(now);
            courseScheduleTeacherSalary.setUpdateTime(now);
            courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
            courseScheduleTeacherSalaries.add(courseScheduleTeacherSalary);

            //学生缴费记录
            CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
            courseScheduleStudentPayment.setGroupType(GroupType.MUSIC);
            courseScheduleStudentPayment.setMusicGroupId(musicGroup.getId());
            courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
            courseScheduleStudentPayment.setUserId(onlineMusicGroupCourseInfo.getStudentId());
            courseScheduleStudentPayment.setExpectPrice(studentSingleCourseCost);
            courseScheduleStudentPayment.setOriginalPrice(studentSingleCourseCost);
            courseScheduleStudentPayment.setActualPrice(studentSingleCourseCost);
            courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
            courseScheduleStudentPayment.setCreateTime(now);
            courseScheduleStudentPayment.setUpdateTime(now);
            courseScheduleStudentPayments.add(courseScheduleStudentPayment);

            //教师签到记录
            TeacherAttendance teacherAttendance = new TeacherAttendance();
            teacherAttendance.setMusicGroupId(musicGroup.getId());
            teacherAttendance.setTeacherId(onlineMusicGroupCourseInfo.getTeacherId());
            teacherAttendance.setClassGroupId(classGroup.getId());
            teacherAttendance.setGroupType(GroupType.MUSIC);
            teacherAttendance.setCourseScheduleId(courseSchedule.getId());
            teacherAttendance.setCreateTime(now);
            teacherAttendances.add(teacherAttendance);
        }
        courseScheduleTeacherSalaryDao.batchInsert(courseScheduleTeacherSalaries);
        courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);
        teacherAttendanceDao.batchInsert(teacherAttendances);

        try {
            courseScheduleService.checkNewCourseSchedules(courses,false,false);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            String errMessage=new String();
            if(e.getMessage().indexOf("主教冲突")!=-1){
                errMessage="抱歉啦，当前所选时段组合，「" + teacher.getRealName() + "」老师已被预约，请重新选择时段或更换老师后重试。";
            }else{
                String courseName=e.getMessage().substring(e.getMessage().indexOf(")-")+2);
                courseName = courseName.substring(0,courseName.indexOf("("));
                errMessage="抱歉啦，当前所选时段组合，与您现有课程「";
                errMessage+=courseName;
                errMessage+="」时段冲突，请选择其他时段重试。";
            }
            throw new BizException(errMessage);
        }

        studentFee.setRemainNetworkClassTimes(studentFee.getRemainNetworkClassTimes()-1);
        musicGroupStudentFeeDao.update(studentFee);

        try{
            List<String> cdstrs=new ArrayList<>();
            for(int i=0;i<courses.size();i++){
                cdstrs.add((i+1)+","+DateUtil.dateToString(courses.get(i).getStartClassTime(), "yyyy年MM月dd日 HH时mm分"));
            }

            Map<Integer, String> userMap = new HashMap<>();
            userMap.put(onlineMusicGroupCourseInfo.getStudentId(), onlineMusicGroupCourseInfo.getStudentId().toString());
            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.MUSIC_NETWORK_CRATE_STUDENT,
                    userMap, null, 0, null, "STUDENT", student.getUsername(), musicGroup.getName(),
                    teacher.getRealName(), DateUtil.dateToString(courses.get(0).getStartClassTime(),"yyyy年MM月dd日 HH时mm分"));

            Map<Integer, String> teacherMap = new HashMap<>();
            teacherMap.put(onlineMusicGroupCourseInfo.getTeacherId(), onlineMusicGroupCourseInfo.getTeacherId().toString());
            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.MUSIC_NETWORK_CRATE_TEACHER,
                    teacherMap, null, 0, null, "TEACHER", teacher.getRealName(), classGroup.getName(),
                    StringUtils.join(cdstrs, ","));
        }catch (Exception e){
            e.printStackTrace();
        }

        studentDao.updateStudentServiceTag(onlineMusicGroupCourseInfo.getStudentId(),null,YesOrNoEnum.YES.getCode());

        Map<Integer,String> userRoleMap = new HashMap<Integer, String>();
        userRoleMap.put(onlineMusicGroupCourseInfo.getStudentId(), null);
        userRoleMap.put(onlineMusicGroupCourseInfo.getTeacherId(), "指导老师");
        
        // 创建群组
        imGroupService.create(classGroup.getId().longValue(), musicGroup.getEducationalTeacherId(), classGroup.getName(), classGroup.getName(), classGroup.getName(), classGroup.getName(), null, "MUSIC");
        imGroupMemberService.join(classGroup.getId().longValue(), userRoleMap);

        List<String> courseTimes = courses.stream().map(c -> DateUtil.dateToString(c.getStartClassTime(), "yyyy-MM-dd HH:mm")).collect(Collectors.toList());

        Map<String, Object> result=new HashMap<>();
        result.put("courseTimes", StringUtils.join(courseTimes,","));
        return result;
    }

    @Override
    public List<SimpleUserDto> getEnableApplyTeachers(Integer studentId, Integer subjectId) {
        if (Objects.isNull(subjectId)) {
            throw new BizException("请选择声部");
        }
        SysUser sysUser = sysUserFeignService.queryUserById(studentId);
        if (Objects.isNull(sysUser)) {
            throw new BizException("用户不存在");
        }
        if (Objects.isNull(sysUser.getOrganId())) {
            throw new BizException("未找到用户分部属性");
        }

        List<Integer> includeTeacherIds = new ArrayList<>();
        List<ExtendTeacherBasicDto> organAndSubjectTeachers = teacherDao.findTeaTeachersByOrganAndSubject3(sysUser.getOrganId(), subjectId);
        if (CollectionUtils.isEmpty(organAndSubjectTeachers)) {
            return new ArrayList<>();
        }

        List<Integer> allTeacherIds = organAndSubjectTeachers.stream().map(TeacherBasicDto::getId).collect(Collectors.toList());

        List<CourseSchedule> userCourses = courseScheduleDao.findUserCourses3(studentId, allTeacherIds);

        if (!CollectionUtils.isEmpty(userCourses)) {
            Map<GroupType, List<CourseSchedule>> courseTypeCourseMap = userCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType));

            List<CourseSchedule> practiceCourses = courseTypeCourseMap.get(GroupType.PRACTICE);
            if (!CollectionUtils.isEmpty(practiceCourses)) {
                for (CourseSchedule practiceCourse : practiceCourses) {
                    if (!includeTeacherIds.contains(practiceCourse.getTeacherId())) {
                        includeTeacherIds.add(practiceCourse.getTeacherId());
                    }
                }
            }

            List<CourseSchedule> vipCourses = courseTypeCourseMap.get(GroupType.VIP);
            if (!CollectionUtils.isEmpty(vipCourses)) {
                for (CourseSchedule vipCourse : vipCourses) {
                    if (!includeTeacherIds.contains(vipCourse.getTeacherId())) {
                        includeTeacherIds.add(vipCourse.getTeacherId());
                    }
                }
            }
            List<CourseSchedule> singleCourses = courseTypeCourseMap.get(GroupType.MUSIC);
            if (!CollectionUtils.isEmpty(singleCourses)) {
                for (CourseSchedule singleCourse : singleCourses) {
                    if (!includeTeacherIds.contains(singleCourse.getTeacherId())) {
                        includeTeacherIds.add(singleCourse.getTeacherId());
                    }
                }
            }
        }

        for (ExtendTeacherBasicDto organAndSubjectTeacher : organAndSubjectTeachers) {
            if (!includeTeacherIds.contains(organAndSubjectTeacher.getId())) {
                includeTeacherIds.add(organAndSubjectTeacher.getId());
            }
        }

        if (CollectionUtils.isEmpty(new ArrayList<>(includeTeacherIds))) {
            return new ArrayList<>();
        }

        List<SimpleUserDto> userInfos = new ArrayList<>();
        Map<Integer, ExtendTeacherBasicDto> idTeacherMap = organAndSubjectTeachers.stream().collect(Collectors.toMap(ExtendTeacherBasicDto::getId, teacher -> teacher));
        for (Integer includeTeacherId : includeTeacherIds) {
            ExtendTeacherBasicDto teacher = idTeacherMap.get(includeTeacherId);
            SimpleUserDto simpleUserDto=new SimpleUserDto(includeTeacherId, teacher.getRealName());
            simpleUserDto.setAvatar(teacher.getAvatar());
            simpleUserDto.setIntroduction(teacher.getIntroduction());
            simpleUserDto.setSubjectNames(teacher.getSubjectNames());
            userInfos.add(simpleUserDto);
        }

        return userInfos;
    }

    @Override
    public Map getTeacherFreeTimes(Integer studentId, Integer teacherId, boolean skipHoliday){
        if (Objects.isNull(teacherId)) {
            throw new BizException("请选择教师");
        }
        SysUser student = sysUserFeignService.queryUserById(studentId);
        if (Objects.isNull(student)) {
            throw new BizException("用户不存在");
        }
        if (Objects.isNull(student.getOrganId())) {
            throw new BizException("未找到用户分部属性");
        }
        Teacher teacher = teacherDao.get(teacherId);
        if (Objects.isNull(teacher)) {
            throw new BizException("教师不存在");
        }
        Map result = new HashMap();
        Set<Date> allTeacherFreeDates = new HashSet<>();

        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        Integer practiceCourseMinutes = practiceCourseMinutesConfig.getParanValue(Integer.class);

        boolean checkTeacherLeaveDate = true;
        SysConfig allTeacherLeaveDataConfig = sysConfigService.findByParamName(SysConfigService.TEACHER_LEAVE_DATA);
        JSONObject allTeacherLeaveData = JSONObject.parseObject(allTeacherLeaveDataConfig.getParanValue());
        if (Objects.isNull(allTeacherLeaveData)) {
            checkTeacherLeaveDate = false;
        }

        Set<String> holidayDays = new HashSet<>();

        if (skipHoliday) {
            SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
            if(Objects.nonNull(holidaySetting)&&StringUtils.isNotBlank(holidaySetting.getParanValue())){
                holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
            }
        }

        Set<Integer> disableApplyWeekNum = new HashSet<>();
        Set<Integer> disableApplyWeekDay = new HashSet<>();

        TeacherFreeTime teacherFreeTime = teacherFreeTimeDao.findTeacherFreeTime(teacherId);
        JSONObject teacherFreeTimes=new JSONObject();
        int holiday = 0;
        if (Objects.nonNull(teacherFreeTime)) {
            if (Objects.nonNull(teacherFreeTime.getHoliday())) {
                holiday = DateUtil.normalWeekNumCalendarWeekNumMap.get(teacherFreeTime.getHoliday());
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getMonday())){
                teacherFreeTimes.put(String.valueOf(Calendar.MONDAY), JSON.parseArray(teacherFreeTime.getMonday()));
            }else{
                disableApplyWeekDay.add(Calendar.MONDAY);
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getTuesday())){
                teacherFreeTimes.put(String.valueOf(Calendar.TUESDAY), JSON.parseArray(teacherFreeTime.getTuesday()));
            }else{
                disableApplyWeekDay.add(Calendar.TUESDAY);
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getWednesday())){
                teacherFreeTimes.put(String.valueOf(Calendar.WEDNESDAY), JSON.parseArray(teacherFreeTime.getWednesday()));
            }else{
                disableApplyWeekDay.add(Calendar.WEDNESDAY);
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getThursday())){
                teacherFreeTimes.put(String.valueOf(Calendar.THURSDAY), JSON.parseArray(teacherFreeTime.getThursday()));
            }else{
                disableApplyWeekDay.add(Calendar.THURSDAY);
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getFriday())){
                teacherFreeTimes.put(String.valueOf(Calendar.FRIDAY), JSON.parseArray(teacherFreeTime.getFriday()));
            }else{
                disableApplyWeekDay.add(Calendar.FRIDAY);
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getSaturday())){
                teacherFreeTimes.put(String.valueOf(Calendar.SATURDAY), JSON.parseArray(teacherFreeTime.getSaturday()));
            }else{
                disableApplyWeekDay.add(Calendar.SATURDAY);
            }
            if(StringUtils.isNotBlank(teacherFreeTime.getSunday())){
                teacherFreeTimes.put(String.valueOf(Calendar.SUNDAY), JSON.parseArray(teacherFreeTime.getSunday()));
            }else{
                disableApplyWeekDay.add(Calendar.SUNDAY);
            }
        }else{
            result.put("teacherFreeDays", new ArrayList<>());
            return result;
        }

        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(now);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        calendar.add(Calendar.DATE, 1);
        Date applyStartDate = calendar.getTime();
        Date applyEndDate = DateUtil.addDays(applyStartDate, 14);
        Date firstMonday = DateUtil.getWeekDayWithDate(applyStartDate, Calendar.MONDAY);
        Date secondSunday = DateUtil.getWeekDayWithDate(applyEndDate, Calendar.SUNDAY);

        List<Date> enableApplyDates = practiceGroupService.getEnableApplyDatesIncludeAllTimes(applyStartDate, applyEndDate);
        List<CourseSchedule> allTeacherCourses = courseScheduleDao.findTeacherCoursesWithDateRange(teacherId, firstMonday, secondSunday);
        allTeacherCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        List<CourseSchedule> applyDateRangeCourses = new ArrayList<>();
        for (int i = 0; i < allTeacherCourses.size(); i++) {
            CourseSchedule teacherCourse = allTeacherCourses.get(i);
            if ((!teacherCourse.getClassDate().before(applyStartDate))
                    && (teacherCourse.getClassDate().before(applyEndDate) || DateUtil.isSameDay(teacherCourse.getClassDate(), applyEndDate))) {
                applyDateRangeCourses.add(teacherCourse);
            }
        }

        JSONObject teacherLeaveData = null;
        if (checkTeacherLeaveDate) {
            teacherLeaveData = allTeacherLeaveData.getJSONObject(teacherId.toString());
        }

        if (Objects.isNull(teacherLeaveData)) {
            checkTeacherLeaveDate = false;
        }

        if (CollectionUtils.isEmpty(applyDateRangeCourses)) {
            for (Date enableApplyDate : enableApplyDates) {
                Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
                if (teacherId == 100473) {
                    checkTeacherLeaveDate = false;
                    Calendar tempCalendar = Calendar.getInstance();
                    tempCalendar.setFirstDayOfWeek(Calendar.MONDAY);
                    tempCalendar.setTime(enableApplyDate);
                    if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
                            || tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                        String date_str = DateUtil.dateToString(enableApplyDate, "yyyy-MM-dd");
                        Date date1 = DateUtil.stringToDate(date_str + " 11:30:00");
                        Date date2 = DateUtil.stringToDate(date_str + " 14:30:00");
                        Date date3 = DateUtil.stringToDate(date_str + " 20:30:00");
                        if (enableApplyDate.before(date2)
                                && enableApplyDateCourseEndTime.after(date1)) {
                            continue;
                        }
                        if (date3.before(enableApplyDateCourseEndTime)) {
                            continue;
                        }
                    }
                    if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                        continue;
                    }
                }
                if (checkTeacherLeaveDate) {
                    String dateStr = DateUtil.dateToString(enableApplyDate, "yyyy-MM-dd");
                    JSONObject leaveDateData = teacherLeaveData.getJSONObject(dateStr);
                    if (Objects.nonNull(leaveDateData)) {
                        Date leaveStartTime = leaveDateData.getDate("leave_start_time");
                        Date leaveEndTime = leaveDateData.getDate("leave_end_time");
                        if (enableApplyDateCourseEndTime.after(leaveStartTime)
                                && enableApplyDate.before(leaveEndTime)) {
                            continue;
                        }
                    }
                }
                calendar.setTime(enableApplyDate);
                int dayOfWeek=calendar.get(Calendar.DAY_OF_WEEK);
                if(disableApplyWeekDay.contains(dayOfWeek)){
                    continue;
                }
                JSONArray teacherWeekDayFreeTimes = teacherFreeTimes.getJSONArray(String.valueOf(dayOfWeek));
                if(Objects.nonNull(teacherWeekDayFreeTimes)){
                    LocalTime enableApplyStartTime=LocalDateTime.ofInstant(enableApplyDate.toInstant(),DateUtil.zoneId).toLocalTime();
                    LocalTime enableApplyEndTime=LocalDateTime.ofInstant(enableApplyDateCourseEndTime.toInstant(),DateUtil.zoneId).toLocalTime();
                    boolean isInclude=false;
                    for (Object teacherWeekDayFreeTimeObject : teacherWeekDayFreeTimes) {
                        JSONObject teacherWeekDayFreeTime=JSONObject.parseObject(teacherWeekDayFreeTimeObject.toString());
                        LocalTime teacherFreeStartTime=LocalTime.parse(teacherWeekDayFreeTime.getString("startTime"),DateUtil.timeFormatter);
                        LocalTime teacherFreeEndTime=LocalTime.parse(teacherWeekDayFreeTime.getString("endTime"),DateUtil.timeFormatter);
                        if(enableApplyEndTime.compareTo(teacherFreeEndTime)<=0
                                &&enableApplyStartTime.compareTo(teacherFreeStartTime)>=0){
                            isInclude=true;
                            break;
                        }
                    }
                    if(!isInclude){
                        continue;
                    }
                }
                if (dayOfWeek != holiday) {
                    allTeacherFreeDates.add(enableApplyDate);
                }
            }
            if (!CollectionUtils.isEmpty(allTeacherFreeDates)) {
                List<Date> tempDates = new ArrayList<>();
                if (CollectionUtils.isEmpty(tempDates)) {
                    tempDates = new ArrayList<>(allTeacherFreeDates);
                }
                tempDates.sort(Comparator.comparing(Date::getTime));
                Map<String, List<String>> rt=new HashMap<>();
                for (Date tempDate : tempDates) {
                    String dateStr = DateUtil.dateToString(tempDate, "yyyy-MM-dd");
                    if(holidayDays.contains(dateStr)){
                        continue;
                    }
                    String timeStr = DateUtil.dateToString(tempDate, "HH:mm:ss");
                    if(!rt.containsKey(dateStr)){
                        rt.put(dateStr, new ArrayList<>());
                    }
                    rt.get(dateStr).add(timeStr);
                }

                result.put("teacherFreeDays", rt);
            } else {
                result.put("teacherFreeDays", new ArrayList<>());
            }
            return result;
        }

        List<Date> tempEnableApplyDates = new ArrayList<>();
        for (Date enableApplyDate : enableApplyDates) {
            Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);

            if (teacherId == 100473) {
                checkTeacherLeaveDate = false;
                Calendar tempCalendar = Calendar.getInstance();
                tempCalendar.setFirstDayOfWeek(Calendar.MONDAY);
                tempCalendar.setTime(enableApplyDate);
                if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
                        || tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                    String date_str = DateUtil.dateToString(enableApplyDate, "yyyy-MM-dd");
                    Date date1 = DateUtil.stringToDate(date_str + " 11:30:00");
                    Date date2 = DateUtil.stringToDate(date_str + " 14:30:00");
                    Date date3 = DateUtil.stringToDate(date_str + " 20:30:00");
                    if (enableApplyDate.before(date2)
                            && enableApplyDateCourseEndTime.after(date1)) {
                        continue;
                    }
                    if (date3.before(enableApplyDateCourseEndTime)) {
                        continue;
                    }
                }
                if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                    continue;
                }
            }
            if (checkTeacherLeaveDate) {
                String dateStr = DateUtil.dateToString(enableApplyDate, "yyyy-MM-dd");
                JSONObject leaveDateData = teacherLeaveData.getJSONObject(dateStr);
                if (Objects.nonNull(leaveDateData)) {
                    Date leaveStartTime = leaveDateData.getDate("leave_start_time");
                    Date leaveEndTime = leaveDateData.getDate("leave_end_time");
                    if (enableApplyDateCourseEndTime.after(leaveStartTime)
                            && enableApplyDate.before(leaveEndTime)) {
                        continue;
                    }
                }
            }
            calendar.setTime(enableApplyDate);

            int dayOfWeek=calendar.get(Calendar.DAY_OF_WEEK);
            if(disableApplyWeekDay.contains(dayOfWeek)){
                continue;
            }
            JSONArray teacherWeekDayFreeTimes = teacherFreeTimes.getJSONArray(String.valueOf(dayOfWeek));
            if(Objects.nonNull(teacherWeekDayFreeTimes)){
                LocalTime enableApplyStartTime=LocalDateTime.ofInstant(enableApplyDate.toInstant(),DateUtil.zoneId).toLocalTime();
                LocalTime enableApplyEndTime=LocalDateTime.ofInstant(enableApplyDateCourseEndTime.toInstant(),DateUtil.zoneId).toLocalTime();
                boolean isInclude=false;
                for (Object teacherWeekDayFreeTimeObject : teacherWeekDayFreeTimes) {
                    JSONObject teacherWeekDayFreeTime=JSONObject.parseObject(teacherWeekDayFreeTimeObject.toString());
                    LocalTime teacherFreeStartTime=LocalTime.parse(teacherWeekDayFreeTime.getString("startTime"),DateUtil.timeFormatter);
                    LocalTime teacherFreeEndTime=LocalTime.parse(teacherWeekDayFreeTime.getString("endTime"),DateUtil.timeFormatter);
                    if(enableApplyEndTime.compareTo(teacherFreeEndTime)<=0
                            &&enableApplyStartTime.compareTo(teacherFreeStartTime)>=0){
                        isInclude=true;
                        break;
                    }
                }
                if(!isInclude){
                    continue;
                }
            }

            if (dayOfWeek == holiday) {
                continue;
            }

            if (!disableApplyWeekNum.contains(calendar.get(Calendar.WEEK_OF_YEAR))) {
                tempEnableApplyDates.add(enableApplyDate);
            }
        }

        applyDateRangeCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
        for (int j = 0; j < applyDateRangeCourses.size(); j++) {
            CourseSchedule preCourseSchedule = applyDateRangeCourses.get(j);
            CourseSchedule backCourseSchedule = j >= applyDateRangeCourses.size() - 1 ? preCourseSchedule : applyDateRangeCourses.get(j + 1);
            if (preCourseSchedule.getEndClassTime().after(backCourseSchedule.getEndClassTime())) {
                backCourseSchedule.setEndClassTime(preCourseSchedule.getEndClassTime());
            }
            if (j == 0) {
                for (Date enableApplyDate : tempEnableApplyDates) {
                    Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
                    if (!enableApplyDateCourseEndTime.after(preCourseSchedule.getStartClassTime())) {
                        allTeacherFreeDates.add(enableApplyDate);
                    }
                }
            }
            if (j == applyDateRangeCourses.size() - 1) {
                for (Date enableApplyDate : tempEnableApplyDates) {
                    if (!enableApplyDate.before(backCourseSchedule.getEndClassTime())) {
                        allTeacherFreeDates.add(enableApplyDate);
                    }
                }
            }
            if (j >= applyDateRangeCourses.size() - 1) {
                break;
            }
            for (Date enableApplyDate : tempEnableApplyDates) {
                Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
                if (!enableApplyDate.before(preCourseSchedule.getEndClassTime())
                        && !enableApplyDateCourseEndTime.after(backCourseSchedule.getStartClassTime())) {
                    allTeacherFreeDates.add(enableApplyDate);
                }
            }
        }
        if (!CollectionUtils.isEmpty(allTeacherFreeDates)) {
            List<Date> tempDates = new ArrayList<>();
            if (CollectionUtils.isEmpty(tempDates)) {
                tempDates = new ArrayList<>(allTeacherFreeDates);
            }
            tempDates.sort(Comparator.comparing(Date::getTime));
            Map<String, List<String>> rt=new HashMap<>();
            for (Date tempDate : tempDates) {
                String dateStr = DateUtil.dateToString(tempDate, "yyyy-MM-dd");
                if(holidayDays.contains(dateStr)){
                    continue;
                }
                String timeStr = DateUtil.dateToString(tempDate, "HH:mm:ss");
                if(!rt.containsKey(dateStr)){
                    rt.put(dateStr, new ArrayList<>());
                }
                rt.get(dateStr).add(timeStr);
            }

            result.put("teacherFreeDays", rt);
        }
        return result;
    }
}
