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

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.dal.page.PracticeGroupQueryInfo;
import com.ym.mec.biz.service.PracticeGroupService;
import com.ym.mec.biz.service.SysConfigService;
import com.ym.mec.biz.service.SysMessageService;
import com.ym.mec.biz.service.TeacherService;
import com.ym.mec.common.dal.BaseDAO;
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.common.page.PageInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.im.ImFeignService;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;

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

@Service
public class PracticeGroupServiceImpl extends BaseServiceImpl<Long, PracticeGroup> implements PracticeGroupService {

    @Autowired
    private PracticeGroupDao practiceGroupDao;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private OrganizationDao organizationDao;
    @Autowired
    private TeacherService teacherService;
    @Autowired
    private EmployeeDao employeeDao;
    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;
    @Autowired
    private ClassGroupTeacherSalaryDao classGroupTeacherSalaryDao;
    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private ImFeignService imFeignService;

    private static Map<Integer, Map<Integer, List<Integer>>> schoolSubjectTeachersMap;

    private static final Set<Integer> GUANGZHOU_SUBJECTIDS = new HashSet<Integer>(Arrays.asList(new Integer[]{2, 4, 5, 12, 13, 15, 23}));
    //广州分部编号
    private static final Integer GUANGZHOU_ORGAN_ID = 3;
    //大连分部编号
    private static final Integer DALIAN_ORGAN_ID = 27;
    //沈阳分部编号
    private static final Integer SHENYANG_ORGAN_ID = 6;

    private static Date activityStartDate, activityEndDate, applyStartDay, courseExpireDate;

    static {
        applyStartDay = DateUtil.stringToDate("2020-02-08 00:00:00");
        activityStartDate = DateUtil.stringToDate("2020-02-09 00:00:00");
        activityEndDate = DateUtil.stringToDate("2020-03-25 00:00:00");
        courseExpireDate = DateUtil.stringToDate("2020-04-01 00:00:00");

        schoolSubjectTeachersMap = new HashMap<>();
        Map<Integer, List<Integer>> subjectTeachersMap1 = new HashMap<>();
        subjectTeachersMap1.put(2, Arrays.asList(new Integer[]{100887, 100353, 100854, 102227}));
        subjectTeachersMap1.put(4, Arrays.asList(new Integer[]{102209, 101110, 102084, 102141, 100753}));
        subjectTeachersMap1.put(5, Arrays.asList(new Integer[]{102140, 100368, 100354}));
        subjectTeachersMap1.put(12, Arrays.asList(new Integer[]{101088, 100360, 100366}));
        subjectTeachersMap1.put(13, Arrays.asList(new Integer[]{100363, 100873}));
        subjectTeachersMap1.put(15, Arrays.asList(new Integer[]{100361, 100358, 102127, 100736}));
        subjectTeachersMap1.put(23, Arrays.asList(new Integer[]{100966, 102143, 101161}));
        Integer[] schoolIds1 = new Integer[]{258, 271, 780, 408, 262, 240, 270, 274, 242, 259, 508, 507, 241, 739, 272, 248, 427, 847, 991};
        for (Integer schoolId : schoolIds1) {
            schoolSubjectTeachersMap.put(schoolId, subjectTeachersMap1);
        }

        Map<Integer, List<Integer>> subjectTeachersMap2 = new HashMap<>();
        subjectTeachersMap2.put(2, Arrays.asList(new Integer[]{100812, 100401, 101683, 100362, 102147}));
        subjectTeachersMap2.put(4, Arrays.asList(new Integer[]{102096, 102145, 101386}));
        subjectTeachersMap2.put(5, Arrays.asList(new Integer[]{100939, 101797, 101809, 102121}));
        subjectTeachersMap2.put(12, Arrays.asList(new Integer[]{100375, 102210, 100698}));
        subjectTeachersMap2.put(13, Arrays.asList(new Integer[]{100873, 100876}));
        subjectTeachersMap2.put(15, Arrays.asList(new Integer[]{102294, 102081, 101111}));
        subjectTeachersMap2.put(23, Arrays.asList(new Integer[]{102142, 102122, 101188}));
        Integer[] schoolIds2 = new Integer[]{928, 1044, 243, 269, 250, 932, 502, 943, 954, 846, 266, 428, 819, 961, 492};
        for (Integer schoolId : schoolIds2) {
            schoolSubjectTeachersMap.put(schoolId, subjectTeachersMap2);
        }

        Map<Integer, List<Integer>> subjectTeachersMap3 = new HashMap<>();
        subjectTeachersMap3.put(2, Arrays.asList(new Integer[]{102139, 101650}));
        subjectTeachersMap3.put(4, Arrays.asList(new Integer[]{101796, 101387}));
        subjectTeachersMap3.put(5, Arrays.asList(new Integer[]{102229, 101388}));
        subjectTeachersMap3.put(12, Arrays.asList(new Integer[]{100806, 101950}));
        subjectTeachersMap3.put(13, Arrays.asList(new Integer[]{100806, 101950}));
        subjectTeachersMap3.put(15, Arrays.asList(new Integer[]{102203, 100640}));
        subjectTeachersMap3.put(23, Arrays.asList(new Integer[]{101915}));
        Integer[] schoolIds3 = new Integer[]{852, 267, 245, 848, 845, 862, 863, 854, 781, 864, 861, 931, 875};
        for (Integer schoolId : schoolIds3) {
            schoolSubjectTeachersMap.put(schoolId, subjectTeachersMap3);
        }
    }

    @Override
    public BaseDAO<Long, PracticeGroup> getDAO() {
        return practiceGroupDao;
    }

    @Override
    public List<CourseScheduleDto> findUserPracticeCourses(Integer userId) {
        return courseScheduleDao.findStudentPracticeCourses(userId);
    }

    @Override
    public Integer searchTeacherId(PracticeGroup practiceGroup) {
        if (Objects.isNull(practiceGroup.getSubjectId())) {
            return null;
        }
        SysUser sysUser = sysUserFeignService.queryUserById(practiceGroup.getStudentId());
        if (Objects.isNull(sysUser)) {
            return null;
        }
        if (Objects.isNull(sysUser.getOrganId())) {
            return null;
        }

        //如果是广州分部的,并且声部满足条件的需要特殊处理
        if (sysUser.getOrganId().equals(GUANGZHOU_ORGAN_ID) && GUANGZHOU_SUBJECTIDS.contains(practiceGroup.getSubjectId())) {
            Integer teacherId = searchTeacherIdForGuangZhou(practiceGroup);
            if (Objects.nonNull(teacherId)) {
                return teacherId;
            }
        } else if (sysUser.getOrganId().equals(DALIAN_ORGAN_ID)) {
            sysUser.setOrganId(SHENYANG_ORGAN_ID);
        }

        List<TeacherBasicDto> organAndSubjectTeachers = teacherDao.findTeaTeachersByOrganAndSubject(sysUser.getOrganId(), practiceGroup.getSubjectId());
        if (CollectionUtils.isEmpty(organAndSubjectTeachers)) {
            return null;
        }

        boolean checkTeacherLeaveDate = true;
        SysConfig allTeacherLeaveDataConfig = sysConfigService.findByParamName(SysConfigService.TEACHER_LEAVE_DATA);
        JSONObject allTeacherLeaveData = JSONObject.parseObject(allTeacherLeaveDataConfig.getParanValue());
        JSONObject organTeacherLeaveData = null;
        if (Objects.nonNull(allTeacherLeaveData)) {
            organTeacherLeaveData = allTeacherLeaveData.getJSONObject(sysUser.getOrganId().toString());
        }
        if (Objects.isNull(organTeacherLeaveData)) {
            checkTeacherLeaveDate = false;
        }

        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        Integer practiceCourseMinutes = practiceCourseMinutesConfig.getParanValue(Integer.class);
        List<Integer> teacherIds = organAndSubjectTeachers.stream().map(TeacherBasicDto::getId).collect(Collectors.toList());
        teacherDao.lockTeachers(teacherIds);
        Date now = new Date();
        Calendar calendar = Calendar.getInstance();
        if (now.before(applyStartDay)) {
            now = applyStartDay;
        }
        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);
        List<Integer> firstTeacherIds = new ArrayList<>();
        List<Integer> secondTeacherIds = new ArrayList<>();
        while (calendar.getTime().before(activityEndDate)) {
            calendar.add(Calendar.DATE, 1);
            Date applyStartDay = calendar.getTime();
            calendar.add(Calendar.DATE, 6);
            Date applyEndDay = calendar.getTime();
            if (applyEndDay.after(activityEndDate)) {
                applyEndDay = activityEndDate;
            }

            boolean excludeFirstTime = practiceGroup.getFirstCourseTime().before(applyStartDay) || (practiceGroup.getFirstCourseTime().after(applyEndDay) && !DateUtil.isSameDay(practiceGroup.getFirstCourseTime(), applyEndDay));
            boolean excludeSecondTime = practiceGroup.getSecondCourseTime().before(applyStartDay) || (practiceGroup.getSecondCourseTime().after(applyEndDay) && !DateUtil.isSameDay(practiceGroup.getFirstCourseTime(), applyEndDay));
            if (excludeFirstTime && excludeSecondTime) {
                continue;
            }

            Date firstMonday = DateUtil.getWeekDayWithDate(applyStartDay, Calendar.MONDAY);
            Date secondMonday = DateUtil.getWeekDayWithDate(applyEndDay, Calendar.MONDAY);
            Date secondSunday = DateUtil.getWeekDayWithDate(applyEndDay, Calendar.SUNDAY);

            List<CourseSchedule> allTeacherCourses = courseScheduleDao.findTeachersCoursesWithDateRange(teacherIds, firstMonday, secondSunday);

            Date firstClassEndTime = DateUtil.addMinutes(practiceGroup.getFirstCourseTime(), practiceCourseMinutes);
            Date secondClassEndTime = DateUtil.addMinutes(practiceGroup.getSecondCourseTime(), practiceCourseMinutes);

            Map<Integer, List<CourseSchedule>> teacherCoursesMap = allTeacherCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getActualTeacherId));
            for (Integer teacherId : teacherIds) {
                if (Objects.nonNull(organTeacherLeaveData)) {
                    checkTeacherLeaveDate = true;
                }
                JSONObject teacherLeaveData = null;
                if (checkTeacherLeaveDate) {
                    teacherLeaveData = organTeacherLeaveData.getJSONObject(teacherId.toString());
                }
                if (Objects.isNull(teacherLeaveData)) {
                    checkTeacherLeaveDate = false;
                }

                if (teacherId == 100473) {
                    checkTeacherLeaveDate = false;
                    Calendar tempCalendar = Calendar.getInstance();
                    tempCalendar.setFirstDayOfWeek(Calendar.MONDAY);
                    tempCalendar.setTime(practiceGroup.getFirstCourseTime());
                    if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
                            || tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                        String date_str = DateUtil.dateToString(practiceGroup.getFirstCourseTime(), "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 (practiceGroup.getFirstCourseTime().before(date2)
                                && firstClassEndTime.after(date1)) {
                            continue;
                        }
                        if (date3.before(firstClassEndTime)) {
                            continue;
                        }
                    }
                    if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                        continue;
                    }

                    tempCalendar.setTime(practiceGroup.getSecondCourseTime());
                    if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY
                            || tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                        String date_str = DateUtil.dateToString(practiceGroup.getSecondCourseTime(), "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 (practiceGroup.getSecondCourseTime().before(date2)
                                && firstClassEndTime.after(date1)) {
                            continue;
                        }
                        if (date3.before(secondClassEndTime)) {
                            continue;
                        }
                    }
                    if (tempCalendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
                        continue;
                    }
                }

                if (checkTeacherLeaveDate) {
                    String dateStr = DateUtil.dateToString(practiceGroup.getFirstCourseTime(), "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 (practiceGroup.getFirstCourseTime().before(leaveEndTime)
                                && firstClassEndTime.after(leaveStartTime)) {
                            continue;
                        }
                    }
                    String dateStr2 = DateUtil.dateToString(practiceGroup.getSecondCourseTime(), "yyyy-MM-dd");
                    JSONObject leaveDateData2 = teacherLeaveData.getJSONObject(dateStr2);
                    if (Objects.nonNull(leaveDateData2)) {
                        Date leaveStartTime = leaveDateData2.getDate("leave_start_time");
                        Date leaveEndTime = leaveDateData2.getDate("leave_end_time");
                        if (practiceGroup.getSecondCourseTime().before(leaveEndTime)
                                && secondClassEndTime.after(leaveStartTime)) {
                            continue;
                        }
                    }
                }

                List<CourseSchedule> teacherCourses = teacherCoursesMap.get(teacherId);
                if (CollectionUtils.isEmpty(teacherCourses)) {
                    if (!excludeFirstTime) {
                        firstTeacherIds.add(teacherId);
                    }
                    if (!excludeSecondTime) {
                        secondTeacherIds.add(teacherId);
                    }
                    continue;
                }

                List<CourseSchedule> firstWeekCourses = new ArrayList<>();
                List<CourseSchedule> secondWeekCourses = new ArrayList<>();
                List<CourseSchedule> applyDateRangeCourses = new ArrayList<>();
                for (CourseSchedule teacherCours : teacherCourses) {
                    if (teacherCours.getClassDate().before(secondMonday)) {
                        firstWeekCourses.add(teacherCours);
                    } else {
                        secondWeekCourses.add(teacherCours);
                    }
                    if (!teacherCours.getClassDate().before(applyStartDay)
                            && (teacherCours.getClassDate().before(applyEndDay) || DateUtil.isSameDay(teacherCours.getClassDate(), applyEndDay))) {
                        applyDateRangeCourses.add(teacherCours);
                    }
                }

                boolean firstWeekEnableApply = true;
                boolean secondWeekEnableApply = true;

                if (!CollectionUtils.isEmpty(firstWeekCourses)) {
                    Map<GroupType, Long> groupTypeCountFirstMap = firstWeekCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType, Collectors.counting()));
                    if (Objects.nonNull(groupTypeCountFirstMap.get(GroupType.PRACTICE)) && groupTypeCountFirstMap.get(GroupType.PRACTICE) >= 80) {
                        firstWeekEnableApply = false;
                    }
                }

                if (!CollectionUtils.isEmpty(firstWeekCourses)) {
                    Map<GroupType, Long> groupTypeCountSecondMap = secondWeekCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType, Collectors.counting()));
                    if (Objects.nonNull(groupTypeCountSecondMap.get(GroupType.PRACTICE)) && groupTypeCountSecondMap.get(GroupType.PRACTICE) >= 80) {
                        secondWeekEnableApply = false;
                    }
                }

                Date enableApplyStartDate = applyStartDay;
                Date enableApplyEndDate = secondSunday;
                if (!firstWeekEnableApply) {
                    enableApplyStartDate = secondMonday;
                }
                if (!secondWeekEnableApply) {
                    enableApplyEndDate = secondMonday;
                }

                if (DateUtil.isSameDay(enableApplyStartDate, enableApplyEndDate)) {
                    continue;
                }

                teacherCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
                boolean enableCreateFirstCourse = true;
                if (practiceGroup.getFirstCourseTime().before(enableApplyStartDate)
                        || practiceGroup.getFirstCourseTime().after(enableApplyEndDate)) {
                    enableCreateFirstCourse = false;
                }
                boolean enableCreateSecondCourse = true;
                if (practiceGroup.getSecondCourseTime().before(enableApplyStartDate)
                        || practiceGroup.getSecondCourseTime().after(enableApplyEndDate)) {
                    enableCreateSecondCourse = false;
                }
                for (int i = 0; i < applyDateRangeCourses.size(); i++) {
                    CourseSchedule preCourseSchedule = applyDateRangeCourses.get(i);

                    if (practiceGroup.getFirstCourseTime().before(preCourseSchedule.getEndClassTime())
                            && firstClassEndTime.after(preCourseSchedule.getStartClassTime())) {
                        enableCreateFirstCourse = false;
                    }

                    if (practiceGroup.getSecondCourseTime().before(preCourseSchedule.getEndClassTime())
                            && secondClassEndTime.after(preCourseSchedule.getStartClassTime())) {
                        enableCreateSecondCourse = false;
                    }
                }
                if (enableCreateFirstCourse) {
                    firstTeacherIds.add(teacherId);
                }
                if (enableCreateSecondCourse) {
                    secondTeacherIds.add(teacherId);
                }
            }
            if (!CollectionUtils.isEmpty(firstTeacherIds) && !CollectionUtils.isEmpty(secondTeacherIds)) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(firstTeacherIds) || CollectionUtils.isEmpty(secondTeacherIds)) {
            return null;
        }

        List<Integer> includeTeacherIds = firstTeacherIds.stream().filter(firstTeacherId -> secondTeacherIds.contains(firstTeacherId)).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(includeTeacherIds)) {
            return null;
        }

        List<CourseScheduleTeacherSalary> studentRelateTeachers = courseScheduleTeacherSalaryDao.findStudentRelateTeachers(practiceGroup.getStudentId(), includeTeacherIds);
        Random random = new Random();
        if (!CollectionUtils.isEmpty(studentRelateTeachers)) {
            Map<GroupType, List<CourseScheduleTeacherSalary>> groupTypeTeachersMap = studentRelateTeachers.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getGroupType));
            List<CourseScheduleTeacherSalary> vipGroupTeachers = groupTypeTeachersMap.get(GroupType.VIP);
            if (!CollectionUtils.isEmpty(vipGroupTeachers)) {
                int randomIndex = random.nextInt(vipGroupTeachers.size());
                return vipGroupTeachers.get(randomIndex).getUserId();
            }
            List<CourseScheduleTeacherSalary> musicGroupTeachers = groupTypeTeachersMap.get(GroupType.MUSIC);
            if (!CollectionUtils.isEmpty(musicGroupTeachers)) {
                int randomIndex = random.nextInt(musicGroupTeachers.size());
                return musicGroupTeachers.get(randomIndex).getUserId();
            }
        }

        List<Map<Integer, Integer>> teacherCourseNumMaps = courseScheduleTeacherSalaryDao.countTeacherCourses(includeTeacherIds, GroupType.PRACTICE);
        HashMap<Integer, Integer> teacherCourseNumMap = (HashMap<Integer, Integer>) MapUtil.convertIntegerMap(teacherCourseNumMaps);
        for (Integer includeTeacherId : includeTeacherIds) {
            if (!teacherCourseNumMap.containsKey(includeTeacherId)) {
                teacherCourseNumMap.put(includeTeacherId, 0);
            }
        }
        List<Integer> temp = new ArrayList<>();
        teacherCourseNumMap.entrySet().stream()
                .sorted((r1, r2) -> r1.getValue().compareTo(r2.getValue()))
                .forEach(result -> temp.add(result.getKey()));
        return temp.get(0);
    }

    @Override
    public Integer searchTeacherIdForGuangZhou(PracticeGroup practiceGroup) {
        List<MusicGroup> userMusicGroups = musicGroupDao.findUserMusicGroups(practiceGroup.getStudentId());
        if (CollectionUtils.isEmpty(userMusicGroups)) {
            return null;
        }

        List<Integer> userSchoolIds = userMusicGroups.stream()
                .filter(musicGroup -> Objects.nonNull(musicGroup.getSchoolId()) && schoolSubjectTeachersMap.containsKey(musicGroup.getSchoolId()))
                .map(MusicGroup::getSchoolId).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(userSchoolIds)) {
            return null;
        }

        Collections.shuffle(userSchoolIds);
        Integer schoolId = userMusicGroups.get(0).getSchoolId();

        List<Integer> teacherIds = schoolSubjectTeachersMap.get(schoolId).get(practiceGroup.getSubjectId());
        teacherDao.lockTeachers(teacherIds);

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

        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        Integer practiceCourseMinutes = practiceCourseMinutesConfig.getParanValue(Integer.class);
        Date now = new Date();
        if (now.before(applyStartDay)) {
            now = applyStartDay;
        }
        Calendar calendar = Calendar.getInstance();
        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);
        List<Integer> firstTeacherIds = new ArrayList<>();
        List<Integer> secondTeacherIds = new ArrayList<>();
        while (calendar.getTime().before(activityEndDate)) {
            calendar.add(Calendar.DATE, 1);
            Date applyStartDay = calendar.getTime();
            calendar.add(Calendar.DATE, 6);
            Date applyEndDay = calendar.getTime();
            if (applyEndDay.after(activityEndDate)) {
                applyEndDay = activityEndDate;
            }
            boolean excludeFirstTime = practiceGroup.getFirstCourseTime().before(applyStartDay) || (practiceGroup.getFirstCourseTime().after(applyEndDay) && !DateUtil.isSameDay(practiceGroup.getFirstCourseTime(), applyEndDay));
            boolean excludeSecondTime = practiceGroup.getSecondCourseTime().before(applyStartDay) || (practiceGroup.getSecondCourseTime().after(applyEndDay) && !DateUtil.isSameDay(practiceGroup.getFirstCourseTime(), applyEndDay));
            if (excludeFirstTime && excludeSecondTime) {
                continue;
            }

            Date firstMonday = DateUtil.getWeekDayWithDate(applyStartDay, Calendar.MONDAY);
            Date secondMonday = DateUtil.getWeekDayWithDate(applyEndDay, Calendar.MONDAY);
            Date secondSunday = DateUtil.getWeekDayWithDate(applyEndDay, Calendar.SUNDAY);

            List<CourseSchedule> allTeacherCourses = courseScheduleDao.findTeachersCoursesWithDateRange(teacherIds, firstMonday, secondSunday);

            Date firstClassEndTime = DateUtil.addMinutes(practiceGroup.getFirstCourseTime(), practiceCourseMinutes);
            Date secondClassEndTime = DateUtil.addMinutes(practiceGroup.getSecondCourseTime(), practiceCourseMinutes);

            Map<Integer, List<CourseSchedule>> teacherCoursesMap = allTeacherCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getActualTeacherId));
            for (Integer teacherId : teacherIds) {
                if (Objects.nonNull(organTeacherLeaveData)) {
                    checkTeacherLeaveDate = true;
                }
                JSONObject teacherLeaveData = null;
                if (checkTeacherLeaveDate) {
                    teacherLeaveData = organTeacherLeaveData.getJSONObject(teacherId.toString());
                }
                if (Objects.isNull(teacherLeaveData)) {
                    checkTeacherLeaveDate = false;
                }

                if (checkTeacherLeaveDate) {
                    String dateStr = DateUtil.dateToString(practiceGroup.getFirstCourseTime(), "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 (practiceGroup.getFirstCourseTime().before(leaveEndTime)
                                && firstClassEndTime.after(leaveStartTime)) {
                            continue;
                        }
                    }
                    String dateStr2 = DateUtil.dateToString(practiceGroup.getSecondCourseTime(), "yyyy-MM-dd");
                    JSONObject leaveDateData2 = teacherLeaveData.getJSONObject(dateStr2);
                    if (Objects.nonNull(leaveDateData2)) {
                        Date leaveStartTime = leaveDateData2.getDate("leave_start_time");
                        Date leaveEndTime = leaveDateData2.getDate("leave_end_time");
                        if (practiceGroup.getSecondCourseTime().before(leaveEndTime)
                                && secondClassEndTime.after(leaveStartTime)) {
                            continue;
                        }
                    }
                }

                List<CourseSchedule> teacherCourses = teacherCoursesMap.get(teacherId);
                if (CollectionUtils.isEmpty(teacherCourses)) {
                    if (!excludeFirstTime) {
                        firstTeacherIds.add(teacherId);
                    }
                    if (!excludeSecondTime) {
                        secondTeacherIds.add(teacherId);
                    }
                    continue;
                }

                List<CourseSchedule> firstWeekCourses = new ArrayList<>();
                List<CourseSchedule> secondWeekCourses = new ArrayList<>();
                List<CourseSchedule> applyDateRangeCourses = new ArrayList<>();
                for (CourseSchedule teacherCours : teacherCourses) {
                    if (teacherCours.getClassDate().before(secondMonday)) {
                        firstWeekCourses.add(teacherCours);
                    } else {
                        secondWeekCourses.add(teacherCours);
                    }
                    if (!teacherCours.getClassDate().before(applyStartDay)
                            && (teacherCours.getClassDate().before(applyEndDay) || DateUtil.isSameDay(teacherCours.getClassDate(), applyEndDay))) {
                        applyDateRangeCourses.add(teacherCours);
                    }
                }

                boolean firstWeekEnableApply = true;
                boolean secondWeekEnableApply = true;

                if (!CollectionUtils.isEmpty(firstWeekCourses)) {
                    Map<GroupType, Long> groupTypeCountFirstMap = firstWeekCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType, Collectors.counting()));
                    if (Objects.nonNull(groupTypeCountFirstMap.get(GroupType.PRACTICE)) && groupTypeCountFirstMap.get(GroupType.PRACTICE) >= 80) {
                        firstWeekEnableApply = false;
                    }
                }

                if (!CollectionUtils.isEmpty(firstWeekCourses)) {
                    Map<GroupType, Long> groupTypeCountSecondMap = secondWeekCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType, Collectors.counting()));
                    if (Objects.nonNull(groupTypeCountSecondMap.get(GroupType.PRACTICE)) && groupTypeCountSecondMap.get(GroupType.PRACTICE) >= 80) {
                        secondWeekEnableApply = false;
                    }
                }

                Date enableApplyStartDate = applyStartDay;
                Date enableApplyEndDate = secondSunday;
                if (!firstWeekEnableApply) {
                    enableApplyStartDate = secondMonday;
                }
                if (!secondWeekEnableApply) {
                    enableApplyEndDate = secondMonday;
                }

                if (DateUtil.isSameDay(enableApplyStartDate, enableApplyEndDate)) {
                    continue;
                }

                teacherCourses.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
                boolean enableCreateFirstCourse = true;
                if (practiceGroup.getFirstCourseTime().before(enableApplyStartDate)
                        || practiceGroup.getFirstCourseTime().after(enableApplyEndDate)) {
                    enableCreateFirstCourse = false;
                }
                boolean enableCreateSecondCourse = true;
                if (practiceGroup.getSecondCourseTime().before(enableApplyStartDate)
                        || practiceGroup.getSecondCourseTime().after(enableApplyEndDate)) {
                    enableCreateSecondCourse = false;
                }

                for (int i = 0; i < applyDateRangeCourses.size(); i++) {
                    CourseSchedule preCourseSchedule = applyDateRangeCourses.get(i);

                    if (practiceGroup.getFirstCourseTime().before(preCourseSchedule.getEndClassTime())
                            && firstClassEndTime.after(preCourseSchedule.getStartClassTime())) {
                        enableCreateFirstCourse = false;
                    }

                    if (practiceGroup.getSecondCourseTime().before(preCourseSchedule.getEndClassTime())
                            && secondClassEndTime.after(preCourseSchedule.getStartClassTime())) {
                        enableCreateSecondCourse = false;
                    }
                }
                if (enableCreateFirstCourse) {
                    firstTeacherIds.add(teacherId);
                }
                if (enableCreateSecondCourse) {
                    secondTeacherIds.add(teacherId);
                }
            }
            if (!CollectionUtils.isEmpty(firstTeacherIds) && !CollectionUtils.isEmpty(secondTeacherIds)) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(firstTeacherIds) || CollectionUtils.isEmpty(secondTeacherIds)) {
            return null;
        }

        List<Integer> includeTeacherIds = firstTeacherIds.stream().filter(firstTeacherId -> secondTeacherIds.contains(firstTeacherId)).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(includeTeacherIds)) {
            return null;
        }

        List<Map<Integer, Integer>> teacherCourseNumMaps = courseScheduleTeacherSalaryDao.countTeacherCourses(includeTeacherIds, GroupType.PRACTICE);
        HashMap<Integer, Integer> teacherCourseNumMap = (HashMap<Integer, Integer>) MapUtil.convertIntegerMap(teacherCourseNumMaps);
        for (Integer includeTeacherId : includeTeacherIds) {
            if (!teacherCourseNumMap.containsKey(includeTeacherId)) {
                teacherCourseNumMap.put(includeTeacherId, 0);
            }
        }
        List<Integer> temp = new ArrayList<>();
        teacherCourseNumMap.entrySet().stream()
                .sorted((r1, r2) -> r1.getValue().compareTo(r2.getValue()))
                .forEach(result -> temp.add(result.getKey()));
        return temp.get(0);
    }

    @Override
    public Map getPracticeApplyParams(Integer userId) {
        Map result = new HashMap();
        SysConfig practiceSubjectIdListConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_SUBJECT_ID_LIST);
        SysConfig practiceApplyStartTimeConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_APPLY_START_TIME);
        SysConfig practiceApplyEndTimeConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_APPLY_END_TIME);
        SysConfig practiceApplyIntervalTimeConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_APPLY_INTERVAL_TIME);
        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        Student student = studentDao.get(userId);
        List<Subject> subjects = subjectDao.findBySubjectByIdList(practiceSubjectIdListConfig.getParanValue());
        List<Integer> subjectIds = Arrays.asList(practiceSubjectIdListConfig.getParanValue().split(",")).stream().mapToInt(idStr -> Integer.valueOf(idStr)).boxed().collect(Collectors.toList());
        List<Integer> userDefaultSubjectIds = Objects.isNull(student) || Objects.isNull(student.getSubjectIdList()) ? null : Arrays.asList(student.getSubjectIdList().split(",")).stream().mapToInt(idStr -> Integer.valueOf(idStr)).boxed().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(userDefaultSubjectIds)) {
            userDefaultSubjectIds = userDefaultSubjectIds.stream().filter(userDefaultSubjectId -> subjectIds.contains(userDefaultSubjectId)).collect(Collectors.toList());
        } else {
            userDefaultSubjectIds = new ArrayList<>();
        }

        Integer applyTimes = practiceGroupDao.countUserPracticeApplyRecord(userId);

        result.put("subjects", subjects);
        result.put("practiceApplyStartTime", practiceApplyStartTimeConfig.getParanValue());
        result.put("practiceApplyEndTime", practiceApplyEndTimeConfig.getParanValue());
        result.put("userDefaultSubjectIds", StringUtils.join(userDefaultSubjectIds.toArray(), ","));
        result.put("practiceApplyIntervalMinutes", practiceApplyIntervalTimeConfig.getParanValue(Integer.class));
        result.put("practiceCourseMinutes", practiceCourseMinutesConfig.getParanValue(Integer.class));
        result.put("enableApply", applyTimes < 1 ? 1 : 0);
        return result;
    }


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

        //如果是广州分部的,并且声部满足条件的需要特殊处理
        if (sysUser.getOrganId().equals(GUANGZHOU_ORGAN_ID) && GUANGZHOU_SUBJECTIDS.contains(subjectId)) {
            List<MusicGroup> userMusicGroups = musicGroupDao.findUserMusicGroups(userId);
            if (!CollectionUtils.isEmpty(userMusicGroups)) {
                Collections.shuffle(userMusicGroups);
                Integer schoolId = userMusicGroups.get(0).getSchoolId();
                if (schoolSubjectTeachersMap.containsKey(schoolId)) {
                    List<Integer> teacherIds = schoolSubjectTeachersMap.get(schoolId).get(subjectId);
                    if (!CollectionUtils.isEmpty(teacherIds)) {
                        return teacherDao.findSimpleTeachers(teacherIds);
                    }
                }
            }
        } else if (sysUser.getOrganId().equals(DALIAN_ORGAN_ID)) {
            sysUser.setOrganId(SHENYANG_ORGAN_ID);
        }

        List<Integer> includeTeacherIds = new ArrayList<>();
        List<ExtendTeacherBasicDto> organAndSubjectTeachers = teacherDao.findTeaTeachersByOrganAndSubject1(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.findUserCourses(userId, allTeacherIds);

        if(!CollectionUtils.isEmpty(userCourses)){
            Map<CourseSchedule.CourseScheduleType, List<CourseSchedule>> courseTypeCourseMap = userCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getType));
            List<CourseSchedule> vipCourses=courseTypeCourseMap.get(CourseSchedule.CourseScheduleType.VIP);
            if(!CollectionUtils.isEmpty(vipCourses)){
                for (CourseSchedule vipCourse : vipCourses) {
                    if(!includeTeacherIds.contains(vipCourse.getTeacherId())){
                        includeTeacherIds.add(vipCourse.getTeacherId());
                    }
                }
            }
            List<CourseSchedule> singleCourses=courseTypeCourseMap.get(CourseSchedule.CourseScheduleType.SINGLE);
            if(!CollectionUtils.isEmpty(singleCourses)){
                for (CourseSchedule singleCourse : singleCourses) {
                    if(!includeTeacherIds.contains(singleCourse.getTeacherId())){
                        includeTeacherIds.add(singleCourse.getTeacherId());
                    }
                }
            }
            List<CourseSchedule> highCourses=courseTypeCourseMap.get(CourseSchedule.CourseScheduleType.HIGH);
            if(!CollectionUtils.isEmpty(highCourses)){
                for (CourseSchedule highCourse : highCourses) {
                    if(!includeTeacherIds.contains(highCourse.getTeacherId())){
                        includeTeacherIds.add(highCourse.getTeacherId());
                    }
                }
            }
        }

        for (ExtendTeacherBasicDto organAndSubjectTeacher : organAndSubjectTeachers) {
            if (!includeTeacherIds.contains(organAndSubjectTeacher.getId())
                &&1 == organAndSubjectTeacher.getIsSupportExtraPracticeLesson()) {
                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);
            userInfos.add(new SimpleUserDto(includeTeacherId,teacher.getRealName()));
        }

        return userInfos;
    }

    @Override
    public Map getTeacherFreeTimes(Integer userId, Integer teacherId, Date firstClassTime) {
        if (Objects.isNull(teacherId)) {
            throw new BizException("请选择教师");
        }
        SysUser student = sysUserFeignService.queryUserById(userId);
        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());
        JSONObject organTeacherLeaveData = null;
        if (Objects.nonNull(allTeacherLeaveData)) {
            organTeacherLeaveData = allTeacherLeaveData.getJSONObject(teacher.getOrganId().toString());
        }
        if (Objects.isNull(organTeacherLeaveData)) {
            checkTeacherLeaveDate = false;
        }

        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.stringToDate("2020-03-24", "yyyy-MM-dd");
        Date firstMonday = DateUtil.getWeekDayWithDate(applyStartDate, Calendar.MONDAY);
        Date secondSunday = DateUtil.getWeekDayWithDate(applyEndDate, Calendar.SUNDAY);

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

        Set<Integer> disableApplyWeekNum = new HashSet<>();
        List<CourseSchedule> applyDateRangeCourses = new ArrayList<>();
        Calendar courseCalendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        int courseWeekNum = 0;
        int practiceCourseNum = 0;
        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);
            }
            courseCalendar.setTime(teacherCourse.getClassDate());
            if(practiceCourseNum>80){
                disableApplyWeekNum.add(courseWeekNum);
            }
            if (courseCalendar.get(Calendar.WEEK_OF_YEAR) != courseWeekNum) {
                courseWeekNum = courseCalendar.get(Calendar.WEEK_OF_YEAR);
                practiceCourseNum = 0;
            }
            if (teacherCourse.getGroupType().equals(GroupType.PRACTICE)) {
                practiceCourseNum+=1;
            }
        }

        if (Objects.nonNull(organTeacherLeaveData)) {
            checkTeacherLeaveDate = true;
        }
        JSONObject teacherLeaveData = null;
        if (checkTeacherLeaveDate) {
            teacherLeaveData = organTeacherLeaveData.getJSONObject(teacherId.toString());
        }

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

        if (CollectionUtils.isEmpty(applyDateRangeCourses)) {
            for (Date enableApplyDate : enableApplyDates) {
                if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                    continue;
                }
                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;
                        }
                    }
                }
                allTeacherFreeDates.add(enableApplyDate);
            }
            if (!CollectionUtils.isEmpty(allTeacherFreeDates)) {
                List<Date> tempDates=new ArrayList<>();
                if(Objects.nonNull(firstClassTime)){
                    calendar.setTime(firstClassTime);
                    calendar.add(Calendar.DATE, -6);
                    calendar.set(Calendar.HOUR_OF_DAY, 0);
                    calendar.set(Calendar.MINUTE, 0);
                    calendar.set(Calendar.SECOND, 0);
                    calendar.set(Calendar.MILLISECOND, 0);
                    applyStartDate=calendar.getTime();
                    calendar.setTime(firstClassTime);
                    calendar.add(Calendar.DATE, 7);
                    calendar.set(Calendar.HOUR_OF_DAY, 0);
                    calendar.set(Calendar.MINUTE, 0);
                    calendar.set(Calendar.SECOND, 0);
                    calendar.set(Calendar.MILLISECOND, 0);
                    applyEndDate=calendar.getTime();
                    for (Date teacherFreeDate : allTeacherFreeDates) {
                        if(!teacherFreeDate.before(applyStartDate)
                            &&!teacherFreeDate.after(applyEndDate)){
                            tempDates.add(teacherFreeDate);
                        }
                    }
                }
                if(CollectionUtils.isEmpty(tempDates)){
                    tempDates=new ArrayList<>(allTeacherFreeDates);
                }
                tempDates.sort(Comparator.comparing(Date::getTime));
                Set<String> days = tempDates.stream()
                        .map(date -> DateUtil.dateToString(date, "yyyy-MM-dd")).collect(Collectors.toSet());
                List<Date> tempDays=days.stream().map(dateStr -> DateUtil.stringToDate(dateStr,"yyyy-MM-dd")).collect(Collectors.toList());
                tempDays.sort(Comparator.comparing(Date::getTime));
                result.put("teacherFreeDays", tempDays.stream().map(day->DateUtil.dateToString(day, "yyyy-MM-dd")).collect(Collectors.toList()));
                result.put("teacherFreeDates", tempDates);
            } else {
                result.put("teacherFreeDays", new ArrayList<>());
            }
            return result;
        }

        List<Date> tempEnableApplyDates = new ArrayList<>();
        for (Date enableApplyDate : enableApplyDates) {
            Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
            if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                continue;
            }
            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);
            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) {
                    if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                        continue;
                    }
                    Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
                    if (!enableApplyDateCourseEndTime.after(preCourseSchedule.getStartClassTime())) {
                        allTeacherFreeDates.add(enableApplyDate);
                    }
                }
            }
            if (j == applyDateRangeCourses.size() - 1) {
                for (Date enableApplyDate : tempEnableApplyDates) {
                    if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                        continue;
                    }
                    if (!enableApplyDate.before(backCourseSchedule.getEndClassTime())) {
                        allTeacherFreeDates.add(enableApplyDate);
                    }
                }
            }
            if (j >= applyDateRangeCourses.size() - 1) {
                break;
            }
            for (Date enableApplyDate : tempEnableApplyDates) {
                if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                    continue;
                }
                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(Objects.nonNull(firstClassTime)){
                calendar.setTime(firstClassTime);
                calendar.add(Calendar.DATE, -6);
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                applyStartDate=calendar.getTime();
                calendar.setTime(firstClassTime);
                calendar.add(Calendar.DATE, 7);
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                applyEndDate=calendar.getTime();
                for (Date teacherFreeDate : allTeacherFreeDates) {
                    if(!teacherFreeDate.before(applyStartDate)
                            &&!teacherFreeDate.after(applyEndDate)){
                        tempDates.add(teacherFreeDate);
                    }
                }
            }
            if(CollectionUtils.isEmpty(tempDates)){
                tempDates=new ArrayList<>(allTeacherFreeDates);
            }
            tempDates.sort(Comparator.comparing(Date::getTime));
            Set<String> days = tempDates.stream()
                    .map(date -> DateUtil.dateToString(date, "yyyy-MM-dd")).collect(Collectors.toSet());
            List<Date> tempDays=days.stream().map(dateStr -> DateUtil.stringToDate(dateStr,"yyyy-MM-dd")).collect(Collectors.toList());
            tempDays.sort(Comparator.comparing(Date::getTime));
            result.put("teacherFreeDays", tempDays.stream().map(day->DateUtil.dateToString(day, "yyyy-MM-dd")).collect(Collectors.toList()));
            result.put("teacherFreeDates", tempDates);
        }
        return result;
    }

    @Override
    public Map getTeachersFreeTimes(Integer userId, Integer subjectId, Date firstClassTime) {
        if (Objects.isNull(subjectId)) {
            throw new BizException("请选择声部");
        }
        SysUser sysUser = sysUserFeignService.queryUserById(userId);
        if (Objects.isNull(sysUser)) {
            throw new BizException("用户不存在");
        }
        if (Objects.isNull(sysUser.getOrganId())) {
            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);
        List<Integer> teacherIds = new ArrayList<>();

        //如果是广州分部的,并且声部满足条件的需要特殊处理
        if (sysUser.getOrganId().equals(GUANGZHOU_ORGAN_ID) && GUANGZHOU_SUBJECTIDS.contains(subjectId)) {
            List<MusicGroup> userMusicGroups = musicGroupDao.findUserMusicGroups(userId);
            if (!CollectionUtils.isEmpty(userMusicGroups)) {
                Collections.shuffle(userMusicGroups);
                Integer schoolId = userMusicGroups.get(0).getSchoolId();
                if (schoolSubjectTeachersMap.containsKey(schoolId)) {
                    teacherIds = schoolSubjectTeachersMap.get(schoolId).get(subjectId);
                }
            }
        } else if (sysUser.getOrganId().equals(DALIAN_ORGAN_ID)) {
            sysUser.setOrganId(SHENYANG_ORGAN_ID);
        }

        if (CollectionUtils.isEmpty(teacherIds)) {
            List<TeacherBasicDto> organAndSubjectTeachers = teacherDao.findTeaTeachersByOrganAndSubject(sysUser.getOrganId(), subjectId);
            if (CollectionUtils.isEmpty(organAndSubjectTeachers)) {
                result.put("teacherFreeDates", new ArrayList<>());
                return result;
            }
            teacherIds = organAndSubjectTeachers.stream().map(TeacherBasicDto::getId).collect(Collectors.toList());
        }
        teacherDao.lockTeachers(teacherIds);

        boolean checkTeacherLeaveDate = true;
        SysConfig allTeacherLeaveDataConfig = sysConfigService.findByParamName(SysConfigService.TEACHER_LEAVE_DATA);
        JSONObject allTeacherLeaveData = JSONObject.parseObject(allTeacherLeaveDataConfig.getParanValue());
        JSONObject organTeacherLeaveData = null;
        if (Objects.nonNull(allTeacherLeaveData)) {
            organTeacherLeaveData = allTeacherLeaveData.getJSONObject(sysUser.getOrganId().toString());
        }
        if (Objects.isNull(organTeacherLeaveData)) {
            checkTeacherLeaveDate = false;
        }

        Date now = new Date();
        if (now.before(applyStartDay)) {
            now = applyStartDay;
        }
        Calendar calendar = Calendar.getInstance();
        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);
        while (calendar.getTime().before(activityEndDate)) {
            calendar.add(Calendar.DATE, 1);
            Date applyStartDay = calendar.getTime();
            calendar.add(Calendar.DATE, 6);
            Date applyEndDay = calendar.getTime();
            if (applyEndDay.after(activityEndDate)) {
                applyEndDay = activityEndDate;
            }
            Date firstMonday = DateUtil.getWeekDayWithDate(applyStartDay, Calendar.MONDAY);
            Date secondMonday = DateUtil.getWeekDayWithDate(applyEndDay, Calendar.MONDAY);
            Date secondSunday = DateUtil.getWeekDayWithDate(applyEndDay, Calendar.SUNDAY);

            List<Date> enableApplyDates = getEnableApplyDates(applyStartDay, applyEndDay);
            List<CourseSchedule> allTeacherCourses = courseScheduleDao.findTeachersCoursesWithDateRange(teacherIds, firstMonday, secondSunday);
            HashSet<Integer> excludeTeacherIds = new HashSet<>();
            if (Objects.nonNull(firstClassTime)) {
                Date firstClassEndTime = DateUtil.addMinutes(firstClassTime, practiceCourseMinutes);
                for (CourseSchedule teacherCourse : allTeacherCourses) {
                    if (firstClassTime.before(teacherCourse.getEndClassTime())
                            && firstClassEndTime.after(teacherCourse.getStartClassTime())) {
                        excludeTeacherIds.add(teacherCourse.getActualTeacherId());
                    }
                }
            }
            Map<Integer, List<CourseSchedule>> teacherCoursesMap = allTeacherCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getActualTeacherId));
            for (Integer teacherId : teacherIds) {
                if (excludeTeacherIds.contains(teacherId)) {
                    continue;
                }
                if (Objects.nonNull(organTeacherLeaveData)) {
                    checkTeacherLeaveDate = true;
                }
                JSONObject teacherLeaveData = null;
                if (checkTeacherLeaveDate) {
                    teacherLeaveData = organTeacherLeaveData.getJSONObject(teacherId.toString());
                }

                if (Objects.isNull(teacherLeaveData)) {
                    checkTeacherLeaveDate = false;
                }
                List<CourseSchedule> teacherCourses = teacherCoursesMap.get(teacherId);
                if (CollectionUtils.isEmpty(teacherCourses)) {
                    for (Date enableApplyDate : enableApplyDates) {
                        if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                            continue;
                        }
                        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;
                                }
                            }
                        }
                        allTeacherFreeDates.add(enableApplyDate);
                    }
                    break;
                }

                List<CourseSchedule> firstWeekCourses = new ArrayList<>();
                List<CourseSchedule> secondWeekCourses = new ArrayList<>();
                List<CourseSchedule> applyDateRangeCourses = new ArrayList<>();
                for (CourseSchedule teacherCours : teacherCourses) {
                    if (teacherCours.getClassDate().before(secondMonday)) {
                        firstWeekCourses.add(teacherCours);
                    } else {
                        secondWeekCourses.add(teacherCours);
                    }
                    if ((!teacherCours.getClassDate().before(applyStartDay))
                            && (teacherCours.getClassDate().before(applyEndDay) || DateUtil.isSameDay(teacherCours.getClassDate(), applyEndDay))) {
                        applyDateRangeCourses.add(teacherCours);
                    }
                }

                boolean firstWeekEnableApply = true;
                boolean secondWeekEnableApply = true;

                if (!CollectionUtils.isEmpty(firstWeekCourses)) {
                    Map<GroupType, Long> groupTypeCountFirstMap = firstWeekCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType, Collectors.counting()));
                    if (Objects.nonNull(groupTypeCountFirstMap.get(GroupType.PRACTICE)) && groupTypeCountFirstMap.get(GroupType.PRACTICE) >= 80) {
                        firstWeekEnableApply = false;
                    }
                }

                if (!CollectionUtils.isEmpty(secondWeekCourses)) {
                    Map<GroupType, Long> groupTypeCountSecondMap = secondWeekCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getGroupType, Collectors.counting()));
                    if (Objects.nonNull(groupTypeCountSecondMap.get(GroupType.PRACTICE)) && groupTypeCountSecondMap.get(GroupType.PRACTICE) >= 80) {
                        secondWeekEnableApply = false;
                    }
                }

                Date enableApplyStartDate = applyStartDay;
                Date enableApplyEndDate = secondSunday;
                if (!firstWeekEnableApply) {
                    enableApplyStartDate = secondMonday;
                }
                if (!secondWeekEnableApply) {
                    enableApplyEndDate = secondMonday;
                }

                if (DateUtil.isSameDay(enableApplyStartDate, enableApplyEndDate)) {
                    continue;
                }

                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;
                            }
                        }
                    }
                    if (!enableApplyDate.before(enableApplyStartDate) && !enableApplyEndDate.before(enableApplyDate)) {
                        tempEnableApplyDates.add(enableApplyDate);
                    }
                }

                if (CollectionUtils.isEmpty(applyDateRangeCourses)) {
                    allTeacherFreeDates = new HashSet<>(tempEnableApplyDates);
                    break;
                }

                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) {
                            if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                                continue;
                            }
                            Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
                            if (!enableApplyDateCourseEndTime.after(preCourseSchedule.getStartClassTime())) {
                                allTeacherFreeDates.add(enableApplyDate);
                            }
                        }
                    }
                    if (j == applyDateRangeCourses.size() - 1) {
                        for (Date enableApplyDate : tempEnableApplyDates) {
                            if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                                continue;
                            }
                            if (!enableApplyDate.before(backCourseSchedule.getEndClassTime())) {
                                allTeacherFreeDates.add(enableApplyDate);
                            }
                        }
                    }
                    if (j >= applyDateRangeCourses.size() - 1) {
                        break;
                    }
                    for (Date enableApplyDate : tempEnableApplyDates) {
                        if (Objects.nonNull(firstClassTime) && DateUtil.isSameDay(enableApplyDate, firstClassTime)) {
                            continue;
                        }
                        Date enableApplyDateCourseEndTime = DateUtil.addMinutes(enableApplyDate, practiceCourseMinutes);
                        if (!enableApplyDate.before(preCourseSchedule.getEndClassTime())
                                && !enableApplyDateCourseEndTime.after(backCourseSchedule.getStartClassTime())) {
                            allTeacherFreeDates.add(enableApplyDate);
                        }
                    }
                }
            }
            if (!CollectionUtils.isEmpty(allTeacherFreeDates)) {
                break;
            }
        }
        if (!CollectionUtils.isEmpty(allTeacherFreeDates)) {
            Set<String> days = allTeacherFreeDates.stream()
                    .map(date -> DateUtil.dateToString(date, "yyyy-MM-dd")).collect(Collectors.toSet());
            result.put("teacherFreeDays", days);
            allTeacherFreeDates = allTeacherFreeDates.stream().sorted().collect(Collectors.toSet());
            result.put("teacherFreeDates", allTeacherFreeDates);
        } else {
            result.put("teacherFreeDays", new ArrayList<>());
        }
        return result;
    }

    @Override
    public List<Date> getEnableApplyDates(Date startDay, Date endDay) {
        List<Date> result = new ArrayList<>();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDay);
        calendar.add(Calendar.DATE, -1);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        SysConfig practiceApplyStartTimeConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_APPLY_START_TIME);
        SysConfig practiceApplyEndTimeConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_APPLY_END_TIME);
        SysConfig practiceApplyIntervalTimeConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_APPLY_INTERVAL_TIME);
        String enableStartTimeStr = practiceApplyStartTimeConfig.getParanValue();
        String enableEndTimeStr = practiceApplyEndTimeConfig.getParanValue();
        Integer practiceApplyIntervalMinutes = practiceApplyIntervalTimeConfig.getParanValue(Integer.class);
        while (!calendar.getTime().after(endDay)) {
            calendar.add(Calendar.DATE, 1);
            calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(enableStartTimeStr.split(":")[0]));
            calendar.set(Calendar.MINUTE, Integer.valueOf(enableStartTimeStr.split(":")[1]));
            Date enableApplyDayStartTime = calendar.getTime();
            calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(enableEndTimeStr.split(":")[0]));
            calendar.set(Calendar.MINUTE, Integer.valueOf(enableEndTimeStr.split(":")[1]));
            Date enableApplyDayEndTime = calendar.getTime();
            result.add(enableApplyDayStartTime);
            Calendar applyStartCalendar = Calendar.getInstance();
            applyStartCalendar.setTime(enableApplyDayStartTime);
            while (true) {
                applyStartCalendar.add(Calendar.MINUTE, practiceApplyIntervalMinutes);
                if (applyStartCalendar.getTime().after(enableApplyDayEndTime)) {
                    break;
                }
                result.add(applyStartCalendar.getTime());
            }
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map practiceApply(PracticeGroup practiceGroup) {
        Map result = new HashMap();
        SysConfig practiceSubjectIdListConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_SUBJECT_ID_LIST);
        if (!Arrays.asList(practiceSubjectIdListConfig.getParanValue().split(",")).contains(practiceGroup.getSubjectId().toString())) {
            result.put("status", "DISABLE_SUBJECT");
            return result;
        }
        Integer practiceCourseMinutes = 25;
        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        if (Objects.nonNull(practiceCourseMinutesConfig)) {
            practiceCourseMinutes = practiceCourseMinutesConfig.getParanValue(Integer.class);
        }
        SysConfig practiceCourseSalaryConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_SALARY);
        Date now = new Date();
        if (practiceGroup.getFirstCourseTime().before(activityStartDate)
                || practiceGroup.getFirstCourseTime().after(activityEndDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        if (practiceGroup.getSecondCourseTime().before(activityStartDate)
                || practiceGroup.getSecondCourseTime().after(activityEndDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        if (DateUtil.isSameDay(practiceGroup.getFirstCourseTime(), practiceGroup.getSecondCourseTime())) {
            result.put("status", "TWO_DATE_ON_ONE_DAY");
            return result;
        }

        List<Date> allCourseDates = new ArrayList<>();
        allCourseDates.add(practiceGroup.getFirstCourseTime());
        allCourseDates.add(practiceGroup.getSecondCourseTime());
        allCourseDates.add(DateUtil.addDays(practiceGroup.getFirstCourseTime(), 7));
        if (DateUtil.isSameDay(allCourseDates.get(1), allCourseDates.get(2))) {
            Date tempDate = allCourseDates.get(2);
            allCourseDates.remove(2);
            allCourseDates.add(DateUtil.addDays(tempDate, 7));
        }
        allCourseDates.add(DateUtil.addDays(practiceGroup.getSecondCourseTime(), 7));
        if (DateUtil.isSameDay(allCourseDates.get(2), allCourseDates.get(3))) {
            Date tempDate = allCourseDates.get(3);
            allCourseDates.remove(3);
            allCourseDates.add(DateUtil.addDays(tempDate, 7));
        }
        if (allCourseDates.get(2).before(activityStartDate)
                || allCourseDates.get(2).after(courseExpireDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        if (allCourseDates.get(3).before(activityStartDate)
                || allCourseDates.get(3).after(courseExpireDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        allCourseDates.sort(Comparator.comparing(Date::getTime));

        studentDao.lockUser(practiceGroup.getStudentId());

        Integer applyTimes = practiceGroupDao.countUserPracticeApplyRecord(practiceGroup.getStudentId());

        if (applyTimes >= 1) {
            result.put("status", "IS_APPLIED");
            return result;
        }
        applyTimes += 1;

        practiceGroup.setCoursesStartDate(allCourseDates.get(0));
        practiceGroup.setCoursesExpireDate(DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        Integer teacherId = searchTeacherId(practiceGroup);
        if (Objects.isNull(teacherId)) {
            result.put("status", "NO_TEACHER");
            return result;
        }
        practiceGroup.setUserId(teacherId);
        Teacher teacher = teacherService.getDetail(teacherId);
        Employee employee = employeeDao.get(teacherId);
        if (Objects.isNull(employee) || StringUtils.isEmpty(employee.getOrganIdList()) || employee.getOrganIdList().contains(",")) {
            practiceGroup.setOrganId(teacher.getTeacherOrganId());
        } else {
            practiceGroup.setOrganId(Integer.parseInt(employee.getOrganIdList()));
        }
        Subject subject = subjectDao.get(practiceGroup.getSubjectId());
        if (Objects.isNull(subject)) {
            result.put("status", "DISABLE_SUBJECT");
            return result;
        }
        SysUser sysUser = sysUserFeignService.queryUserById(practiceGroup.getStudentId());
        practiceGroup.setName(subject.getName() + "•" + sysUser.getUsername());
        practiceGroup.setSingleClassMinutes(practiceCourseMinutes);
        practiceGroupDao.insert(practiceGroup);

        //创建班级信息
        ClassGroup classGroup = new ClassGroup();
        classGroup.setSubjectIdList(practiceGroup.getSubjectId().toString());
        classGroup.setExpectStudentNum(1);
        classGroup.setStudentNum(1);
        classGroup.setName(practiceGroup.getName());
        classGroup.setTotalClassTimes(allCourseDates.size());
        classGroup.setType(ClassGroupTypeEnum.PRACTICE);
        classGroup.setDelFlag(0);
        classGroup.setGroupType(GroupType.PRACTICE);
        classGroup.setMusicGroupId(practiceGroup.getId().toString());
        classGroup.setCreateTime(now);
        classGroup.setUpdateTime(now);
        classGroupDao.insert(classGroup);

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

        //创建班级与老师课酬记录
        ClassGroupTeacherSalary classGroupTeacherSalary = new ClassGroupTeacherSalary();
        classGroupTeacherSalary.setMusicGroupId(practiceGroup.getId().toString());
        classGroupTeacherSalary.setClassGroupId(classGroup.getId());
        classGroupTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
        classGroupTeacherSalary.setUserId(teacherId);
        classGroupTeacherSalary.setSalary(new BigDecimal(practiceCourseSalaryConfig.getParanValue(Integer.class)));
        classGroupTeacherSalary.setOnlineClassesSalary(new BigDecimal(practiceCourseSalaryConfig.getParanValue(Integer.class)));
        classGroupTeacherSalary.setGroupType(GroupType.PRACTICE);
        classGroupTeacherSalary.setCreateTime(now);
        classGroupTeacherSalary.setUpdateTime(now);
        classGroupTeacherSalaryDao.insert(classGroupTeacherSalary);

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

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

        for (Date courseDate : allCourseDates) {
            //课表
            CourseSchedule courseSchedule = new CourseSchedule();
            courseSchedule.setMusicGroupId(practiceGroup.getId().toString());
            courseSchedule.setClassGroupId(classGroup.getId());
            courseSchedule.setStatus(CourseStatusEnum.NOT_START);
            courseSchedule.setClassDate(courseDate);
            courseSchedule.setStartClassTime(courseDate);
            courseSchedule.setEndClassTime(DateUtil.addMinutes(courseDate, practiceCourseMinutes));
            courseSchedule.setTeacherId(teacherId);
            courseSchedule.setActualTeacherId(teacherId);
            courseSchedule.setCreateTime(now);
            courseSchedule.setUpdateTime(now);
            courseSchedule.setTeachMode(TeachModeEnum.ONLINE);
            courseSchedule.setType(CourseSchedule.CourseScheduleType.PRACTICE);
            courseSchedule.setGroupType(GroupType.PRACTICE);
            courseSchedule.setName(practiceGroup.getName());
            courseScheduleDao.insert(courseSchedule);

            //课程与老师薪水表
            CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
            courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
            courseScheduleTeacherSalary.setGroupType(GroupType.PRACTICE);
            courseScheduleTeacherSalary.setMusicGroupId(practiceGroup.getId().toString());
            courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
            courseScheduleTeacherSalary.setUserId(teacherId);
            courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(practiceCourseSalaryConfig.getParanValue()));
            courseScheduleTeacherSalary.setCreateTime(now);
            courseScheduleTeacherSalary.setUpdateTime(now);
            courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
            courseScheduleTeacherSalaries.add(courseScheduleTeacherSalary);

            //学生缴费记录
            CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
            courseScheduleStudentPayment.setGroupType(GroupType.PRACTICE);
            courseScheduleStudentPayment.setMusicGroupId(practiceGroup.getId().toString());
            courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
            courseScheduleStudentPayment.setUserId(practiceGroup.getStudentId());
            courseScheduleStudentPayment.setExpectPrice(BigDecimal.ZERO);
            courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
            courseScheduleStudentPayment.setCreateTime(now);
            courseScheduleStudentPayment.setUpdateTime(now);
            courseScheduleStudentPayments.add(courseScheduleStudentPayment);

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

        Student student = studentDao.get(practiceGroup.getStudentId());
        if (Objects.isNull(student)) {
            student = new Student();
            student.setUserId(practiceGroup.getStudentId());
            student.setSubjectIdList(practiceGroup.getSubjectId().toString());
            studentDao.insert(student);
        } else {
            if (Objects.isNull(student.getSubjectIdList())) {
                student.setSubjectIdList(practiceGroup.getSubjectId().toString());
            } else {
                String[] studentIdStrings = student.getSubjectIdList().split(",");
                List<String> studentIds = new ArrayList<>(Arrays.asList(studentIdStrings));
                if (!studentIds.contains(practiceGroup.getSubjectId().toString())) {
                    studentIds.add(practiceGroup.getSubjectId().toString());
                }
                student.setSubjectIdList(StringUtils.join(studentIds.toArray(), ","));
            }
            studentDao.update(student);
        }

        List<CourseSchedule> studentRepeatCourse1 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(0), DateUtil.addMinutes(allCourseDates.get(2), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse1)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
//            throw new BizException("您预约的时间端和您现有的课程冲突");
        }
        List<CourseSchedule> studentRepeatCourse2 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(1), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse2)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
//            throw new BizException("您预约的时间端和您现有的课程冲突");
        }
        List<CourseSchedule> studentRepeatCourse3 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(2), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse3)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
//            throw new BizException("您预约的时间端和您现有的课程冲突");
        }
        List<CourseSchedule> studentRepeatCourse4 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(3), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse4)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
//            throw new BizException("您预约的时间端和您现有的课程冲突");
        }

        //推送
        List<CourseSchedule> courseSchedules1 = courseScheduleDao.findTeacherCoursesWithIncludeDateRange(teacherId, allCourseDates.get(2), DateUtil.addMinutes(allCourseDates.get(2), practiceCourseMinutes));
        List<CourseSchedule> courseSchedules2 = courseScheduleDao.findTeacherCoursesWithIncludeDateRange(teacherId, allCourseDates.get(3), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (!CollectionUtils.isEmpty(courseSchedules1) || !CollectionUtils.isEmpty(courseSchedules2)) {
            if (courseSchedules1 == null) {
                courseSchedules1 = new ArrayList<>();
            }
            if (courseSchedules2 == null) {
                courseSchedules2 = new ArrayList<>();
            }
            courseSchedules1.addAll(courseSchedules2);
            List<String> courseDates = new ArrayList<>();
            List<String> courseNames = new ArrayList<>();
            for (int i = 0; i < courseSchedules1.size(); i++) {
                if (courseSchedules1.get(i).getGroupType().equals(GroupType.PRACTICE)) {
                    if (courseSchedules1.get(i).getMusicGroupId().equals(practiceGroup.getId().toString())) {
                        continue;
                    } else {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        result.put("status", "TEACHER_PRACTICE_REPEAT");
                        return result;
//                        throw new BizException("指派的老师存在课程冲突");
                    }
                }
                courseDates.add(DateUtil.dateToString(courseSchedules1.get(i).getStartClassTime(), "yyyy-MM-dd HH:mm:ss"));
                courseNames.add(courseSchedules1.get(i).getName());
            }
            if (!CollectionUtils.isEmpty(courseDates)) {
                String courseDatesStr = StringUtils.join(courseDates, "、");
                String courseNamesStr = StringUtils.join(courseNames, "、");
                Map<Integer, String> teacherMap = new HashMap<>();
                teacherMap.put(teacherId, teacherId.toString());
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.PUSH_TEACHER_COURSE_COLLIDE,
                        teacherMap, null, 0, null, "TEACHER", Objects.isNull(sysUser.getUsername()) ? sysUser.getPhone() : sysUser.getUsername(), courseDatesStr, courseNamesStr, courseNamesStr);
            }
        }

        List<ImGroupMember> imGroupMemberList = new ArrayList<>();
        imGroupMemberList.add(new ImGroupMember(practiceGroup.getUserId().toString()));
        imGroupMemberList.add(new ImGroupMember(practiceGroup.getStudentId().toString()));
        ImGroupMember[] imGroupMembers = imGroupMemberList.toArray(new ImGroupMember[imGroupMemberList.size()]);
        // 创建群组
        imFeignService.groupCreate(new ImGroupModel(classGroup.getId().toString(), imGroupMembers, classGroup.getName()));

        result.put("teacherName", teacher.getRealName());
        result.put("enableApply", applyTimes < 1 ? 1 : 0);
        result.put("status", "SUCCESS");
        return result;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map practiceApply2(PracticeGroup practiceGroup) {
        if(Objects.isNull(practiceGroup.getUserId())){
            throw new BizException("请选择老师");
        }
        Map result = new HashMap();
        SysConfig practiceSubjectIdListConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_SUBJECT_ID_LIST);
        if (!Arrays.asList(practiceSubjectIdListConfig.getParanValue().split(",")).contains(practiceGroup.getSubjectId().toString())) {
            result.put("status", "DISABLE_SUBJECT");
            return result;
        }
        Integer practiceCourseMinutes = 25;
        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        if (Objects.nonNull(practiceCourseMinutesConfig)) {
            practiceCourseMinutes = practiceCourseMinutesConfig.getParanValue(Integer.class);
        }
        SysConfig practiceCourseSalaryConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_SALARY);
        Date now = new Date();
        if (practiceGroup.getFirstCourseTime().before(activityStartDate)
                || practiceGroup.getFirstCourseTime().after(activityEndDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        if (practiceGroup.getSecondCourseTime().before(activityStartDate)
                || practiceGroup.getSecondCourseTime().after(activityEndDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        if (DateUtil.isSameDay(practiceGroup.getFirstCourseTime(), practiceGroup.getSecondCourseTime())) {
            result.put("status", "TWO_DATE_ON_ONE_DAY");
            return result;
        }

        List<Date> allCourseDates = new ArrayList<>();
        allCourseDates.add(practiceGroup.getFirstCourseTime());
        allCourseDates.add(practiceGroup.getSecondCourseTime());
        allCourseDates.add(DateUtil.addDays(practiceGroup.getFirstCourseTime(), 7));
        if (DateUtil.isSameDay(allCourseDates.get(1), allCourseDates.get(2))) {
            Date tempDate = allCourseDates.get(2);
            allCourseDates.remove(2);
            allCourseDates.add(DateUtil.addDays(tempDate, 7));
        }
        allCourseDates.add(DateUtil.addDays(practiceGroup.getSecondCourseTime(), 7));
        if (DateUtil.isSameDay(allCourseDates.get(2), allCourseDates.get(3))) {
            Date tempDate = allCourseDates.get(3);
            allCourseDates.remove(3);
            allCourseDates.add(DateUtil.addDays(tempDate, 7));
        }
        if (allCourseDates.get(2).before(activityStartDate)
                || allCourseDates.get(2).after(courseExpireDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        if (allCourseDates.get(3).before(activityStartDate)
                || allCourseDates.get(3).after(courseExpireDate)) {
            result.put("status", "APPLY_DATE_OVERFLOW");
            return result;
        }
        allCourseDates.sort(Comparator.comparing(Date::getTime));

        studentDao.lockUser(practiceGroup.getStudentId());
        studentDao.lockUser(practiceGroup.getUserId());

        Integer applyTimes = practiceGroupDao.countUserPracticeApplyRecord(practiceGroup.getStudentId());

        if (applyTimes >= 1) {
            result.put("status", "IS_APPLIED");
            return result;
        }
        applyTimes += 1;

        SysUser sysUser = sysUserFeignService.queryUserById(practiceGroup.getStudentId());

        practiceGroup.setCoursesStartDate(allCourseDates.get(0));
        practiceGroup.setCoursesExpireDate(DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        Teacher teacher = teacherService.getDetail(practiceGroup.getUserId());
        if(Objects.isNull(teacher)){
            throw new BizException("老师不存在");
        }

        List<SimpleUserDto> enableApplyTeachers = getEnableApplyTeachers(practiceGroup.getStudentId(), practiceGroup.getSubjectId());
        Set<Integer> enableApplyTeacherIds = enableApplyTeachers.stream().map(SimpleUserDto::getUserId).collect(Collectors.toSet());
        if(!enableApplyTeacherIds.contains(practiceGroup.getUserId())){
            throw new BizException("预约失败，老师选择错误，请重试");
        }

        practiceGroup.setOrganId(sysUser.getOrganId());

        Subject subject = subjectDao.get(practiceGroup.getSubjectId());
        if (Objects.isNull(subject)) {
            result.put("status", "DISABLE_SUBJECT");
            return result;
        }
        practiceGroup.setName(subject.getName() + "•" + sysUser.getUsername());
        practiceGroup.setSingleClassMinutes(practiceCourseMinutes);
        practiceGroupDao.insert(practiceGroup);

        //创建班级信息
        ClassGroup classGroup = new ClassGroup();
        classGroup.setSubjectIdList(practiceGroup.getSubjectId().toString());
        classGroup.setExpectStudentNum(1);
        classGroup.setStudentNum(1);
        classGroup.setName(practiceGroup.getName());
        classGroup.setTotalClassTimes(allCourseDates.size());
        classGroup.setType(ClassGroupTypeEnum.PRACTICE);
        classGroup.setDelFlag(0);
        classGroup.setGroupType(GroupType.PRACTICE);
        classGroup.setMusicGroupId(practiceGroup.getId().toString());
        classGroup.setCreateTime(now);
        classGroup.setUpdateTime(now);
        classGroupDao.insert(classGroup);

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

        //创建班级与老师课酬记录
        ClassGroupTeacherSalary classGroupTeacherSalary = new ClassGroupTeacherSalary();
        classGroupTeacherSalary.setMusicGroupId(practiceGroup.getId().toString());
        classGroupTeacherSalary.setClassGroupId(classGroup.getId());
        classGroupTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
        classGroupTeacherSalary.setUserId(practiceGroup.getUserId());
        classGroupTeacherSalary.setSalary(new BigDecimal(practiceCourseSalaryConfig.getParanValue(Integer.class)));
        classGroupTeacherSalary.setOnlineClassesSalary(new BigDecimal(practiceCourseSalaryConfig.getParanValue(Integer.class)));
        classGroupTeacherSalary.setGroupType(GroupType.PRACTICE);
        classGroupTeacherSalary.setCreateTime(now);
        classGroupTeacherSalary.setUpdateTime(now);
        classGroupTeacherSalaryDao.insert(classGroupTeacherSalary);

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

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

        for (Date courseDate : allCourseDates) {
            //课表
            CourseSchedule courseSchedule = new CourseSchedule();
            courseSchedule.setMusicGroupId(practiceGroup.getId().toString());
            courseSchedule.setClassGroupId(classGroup.getId());
            courseSchedule.setStatus(CourseStatusEnum.NOT_START);
            courseSchedule.setClassDate(courseDate);
            courseSchedule.setStartClassTime(courseDate);
            courseSchedule.setEndClassTime(DateUtil.addMinutes(courseDate, practiceCourseMinutes));
            courseSchedule.setTeacherId(practiceGroup.getUserId());
            courseSchedule.setActualTeacherId(practiceGroup.getUserId());
            courseSchedule.setCreateTime(now);
            courseSchedule.setUpdateTime(now);
            courseSchedule.setTeachMode(TeachModeEnum.ONLINE);
            courseSchedule.setType(CourseSchedule.CourseScheduleType.PRACTICE);
            courseSchedule.setGroupType(GroupType.PRACTICE);
            courseSchedule.setName(practiceGroup.getName());
            courseScheduleDao.insert(courseSchedule);

            //课程与老师薪水表
            CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
            courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
            courseScheduleTeacherSalary.setGroupType(GroupType.PRACTICE);
            courseScheduleTeacherSalary.setMusicGroupId(practiceGroup.getId().toString());
            courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
            courseScheduleTeacherSalary.setUserId(practiceGroup.getUserId());
            courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(practiceCourseSalaryConfig.getParanValue()));
            courseScheduleTeacherSalary.setCreateTime(now);
            courseScheduleTeacherSalary.setUpdateTime(now);
            courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
            courseScheduleTeacherSalaries.add(courseScheduleTeacherSalary);

            //学生缴费记录
            CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
            courseScheduleStudentPayment.setGroupType(GroupType.PRACTICE);
            courseScheduleStudentPayment.setMusicGroupId(practiceGroup.getId().toString());
            courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
            courseScheduleStudentPayment.setUserId(practiceGroup.getStudentId());
            courseScheduleStudentPayment.setExpectPrice(BigDecimal.ZERO);
            courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
            courseScheduleStudentPayment.setCreateTime(now);
            courseScheduleStudentPayment.setUpdateTime(now);
            courseScheduleStudentPayments.add(courseScheduleStudentPayment);

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

        Student student = studentDao.get(practiceGroup.getStudentId());
        if (Objects.isNull(student)) {
            student = new Student();
            student.setUserId(practiceGroup.getStudentId());
            student.setSubjectIdList(practiceGroup.getSubjectId().toString());
            studentDao.insert(student);
        } else {
            if (Objects.isNull(student.getSubjectIdList())) {
                student.setSubjectIdList(practiceGroup.getSubjectId().toString());
            } else {
                String[] studentIdStrings = student.getSubjectIdList().split(",");
                List<String> studentIds = new ArrayList<>(Arrays.asList(studentIdStrings));
                if (!studentIds.contains(practiceGroup.getSubjectId().toString())) {
                    studentIds.add(practiceGroup.getSubjectId().toString());
                }
                student.setSubjectIdList(StringUtils.join(studentIds.toArray(), ","));
            }
            studentDao.update(student);
        }

        List<CourseSchedule> studentRepeatCourse1 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(0), DateUtil.addMinutes(allCourseDates.get(2), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse1)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
        }
        List<CourseSchedule> studentRepeatCourse2 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(1), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse2)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
        }
        List<CourseSchedule> studentRepeatCourse3 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(2), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse3)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
        }
        List<CourseSchedule> studentRepeatCourse4 = courseScheduleDao.findStudentCoursesWithIncludeDateRange(practiceGroup.getStudentId(), allCourseDates.get(3), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (CollectionUtils.isEmpty(studentRepeatCourse4)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("status", "STUDENT_COURSE_REPEAT");
            return result;
        }

        //推送
        List<CourseSchedule> courseSchedules1 = courseScheduleDao.findTeacherCoursesWithIncludeDateRange(practiceGroup.getUserId(), allCourseDates.get(2), DateUtil.addMinutes(allCourseDates.get(2), practiceCourseMinutes));
        List<CourseSchedule> courseSchedules2 = courseScheduleDao.findTeacherCoursesWithIncludeDateRange(practiceGroup.getUserId(), allCourseDates.get(3), DateUtil.addMinutes(allCourseDates.get(3), practiceCourseMinutes));
        if (!CollectionUtils.isEmpty(courseSchedules1) || !CollectionUtils.isEmpty(courseSchedules2)) {
            if (courseSchedules1 == null) {
                courseSchedules1 = new ArrayList<>();
            }
            if (courseSchedules2 == null) {
                courseSchedules2 = new ArrayList<>();
            }
            courseSchedules1.addAll(courseSchedules2);
            List<String> courseDates = new ArrayList<>();
            List<String> courseNames = new ArrayList<>();
            for (int i = 0; i < courseSchedules1.size(); i++) {
                if (courseSchedules1.get(i).getGroupType().equals(GroupType.PRACTICE)) {
                    if (courseSchedules1.get(i).getMusicGroupId().equals(practiceGroup.getId().toString())) {
                        continue;
                    } else {
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        result.put("status", "TEACHER_PRACTICE_REPEAT");
                        return result;
                    }
                }
                courseDates.add(DateUtil.dateToString(courseSchedules1.get(i).getStartClassTime(), "yyyy-MM-dd HH:mm:ss"));
                courseNames.add(courseSchedules1.get(i).getName());
            }
            if (!CollectionUtils.isEmpty(courseDates)) {
                String courseDatesStr = StringUtils.join(courseDates, "、");
                String courseNamesStr = StringUtils.join(courseNames, "、");
                Map<Integer, String> teacherMap = new HashMap<>();
                teacherMap.put(practiceGroup.getUserId(), practiceGroup.getUserId().toString());
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.PUSH_TEACHER_COURSE_COLLIDE,
                        teacherMap, null, 0, null, "TEACHER", Objects.isNull(sysUser.getUsername()) ? sysUser.getPhone() : sysUser.getUsername(), courseDatesStr, courseNamesStr, courseNamesStr);
            }
        }

        List<ImGroupMember> imGroupMemberList = new ArrayList<>();
        imGroupMemberList.add(new ImGroupMember(practiceGroup.getUserId().toString()));
        imGroupMemberList.add(new ImGroupMember(practiceGroup.getStudentId().toString()));
        ImGroupMember[] imGroupMembers = imGroupMemberList.toArray(new ImGroupMember[imGroupMemberList.size()]);
        // 创建群组
        imFeignService.groupCreate(new ImGroupModel(classGroup.getId().toString(), imGroupMembers, classGroup.getName()));

        result.put("teacherName", teacher.getRealName());
        result.put("enableApply", applyTimes < 1 ? 1 : 0);
        result.put("status", "SUCCESS");
        return result;
    }

    @Override
    public PageInfo<PracticeGroupDto> findPracticeGroups(PracticeGroupQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        List<PracticeGroupDto> dataList = null;
        int count = practiceGroupDao.countPracticeGroupByOrgan(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = practiceGroupDao.findAllByOrgan(params);
            if (dataList != null && dataList.size() > 0) {
                List<Integer> subjectIds = dataList.stream().map(practiceGroup -> practiceGroup.getSubjectId()).distinct().collect(Collectors.toList());
                List<Integer> organIds = dataList.stream().map(practiceGroup -> practiceGroup.getOrganId()).distinct().collect(Collectors.toList());
                List<String> practiceGroupIds = dataList.stream().map(e -> String.valueOf(e.getId())).distinct().collect(Collectors.toList());

                List<ClassGroup> classGroupsByVipGroups = classGroupDao
                        .findByMusicGroupsAndType(practiceGroupIds.stream().map(groupId -> String.valueOf(groupId)).collect(Collectors.toList()),
                                GroupType.PRACTICE.getCode());
                Map<String, ClassGroup> vipGroupClassGroupMap = classGroupsByVipGroups.stream().collect(Collectors.toMap(ClassGroup::getMusicGroupId, classGroup -> classGroup));
                //当前课时，总课时
//                List<Map<Long, Integer>> countGroupOverCourse = courseScheduleDao.countGroupOverCourse(practiceGroupIds,GroupType.PRACTICE.getCode());
                Map<String, Long> totalClassTimeMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalCourseScheduleNum(practiceGroupIds, GroupType.PRACTICE.getCode()));
                Map<String, Long> currentClassTimeMap = MapUtil.convertIntegerMap(courseScheduleDao.countCourseScheduleNum(practiceGroupIds, GroupType.PRACTICE.getCode()));
                //声部名称列表
                Map<Long, String> subjectNames = MapUtil.convertMybatisMap(subjectDao.findBySubjecIds(StringUtils.join(subjectIds, ",")));
                Map<Integer, String> organNames = MapUtil.convertMybatisMap(organizationDao.findOrganNameMap(StringUtils.join(organIds, ",")));
                dataList.forEach(e -> {
                    e.setSubjectName(subjectNames.get(e.getSubjectId().intValue()));
                    e.setOrganName(organNames.get(e.getOrganId()));
                    ClassGroup classGroup = vipGroupClassGroupMap.get(e.getId().toString());
                    if (Objects.nonNull(classGroup)) {
                        e.setStudentNum(classGroup.getStudentNum());
                    }
                    Long aLong = totalClassTimeMap.get(e.getId() + "");
                    e.setTotalClassTimes(aLong == null ? 0 : aLong.intValue());
                    Long aLong1 = currentClassTimeMap.get(e.getId() + "");
                    e.setCurrentClassTimes(aLong1 == null ? 0 : aLong1.intValue());
                });
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public Object findPracticeGroupCourseSchedules(PracticeGroupQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        if (Objects.isNull(queryInfo.getPracticeId())) {
            throw new BizException("请指定陪练课课程");
        }

        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);

        PracticeGroup practiceGroup = practiceGroupDao.get(queryInfo.getPracticeId());
        if (Objects.isNull(practiceGroup)) {
            throw new BizException("指定的陪练课不存在");
        }
        List<CourseSchedule> dataList = courseScheduleDao.findGroupCourseSchedules(practiceGroup.getId(), GroupType.PRACTICE.getCode());
        int count = dataList.size();
        if (count > 0) {
            pageInfo.setTotal(count);
            List<Long> courseScheduleIds = dataList.stream()
                    .map(courseSchedule -> courseSchedule.getId())
                    .distinct().collect(Collectors.toList());
            List<Map<Long, Integer>> courseSettlementMaps = courseScheduleTeacherSalaryDao.checkCoursesIsSettlement(courseScheduleIds);
            Map<Long, Long> courseSettlementMap = MapUtil.convertIntegerMap(courseSettlementMaps);
            //获取课程实际上课老师姓名
            Map<Long, String> teacherNames = MapUtil.convertIntegerMap(courseScheduleDao.queryTeacherName(courseScheduleIds));
            dataList.forEach(e -> {
                Long isSettlement = courseSettlementMap.get(e.getId().longValue());
                e.setTeacherName(teacherNames.get(e.getId()));
                if (Objects.isNull(isSettlement) || isSettlement <= 0) {
                    e.setIsSettlement(0);
                } else {
                    e.setIsSettlement(1);
                }
            });
        }
        pageInfo.setRows(dataList);
        Map<String, Object> result = new HashMap<>();
        result.put("pageInfo", pageInfo);
        return result;
    }

}
