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

import com.alibaba.fastjson.JSON;
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.auth.api.entity.SysUserRole;
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.CourseScheduleQueryInfo;
import com.ym.mec.biz.dal.page.EndCourseScheduleQueryInfo;
import com.ym.mec.biz.dal.page.StudentCourseScheduleRecordQueryInfo;
import com.ym.mec.biz.dal.page.VipGroupQueryInfo;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.dal.BaseDAO;
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.jiari.JiaRiFeignService;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext.MessageSender;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import feign.codec.DecodeException;
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class CourseScheduleServiceImpl extends BaseServiceImpl<Long, CourseSchedule> implements CourseScheduleService {

    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private CourseScheduleComplaintsDao courseScheduleComplaintsDao;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private StudentAttendanceDao studentAttendanceDao;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private CourseScheduleTeacherSalaryService courseScheduleTeacherSalaryService;
    @Autowired
    private VipGroupDao vipGroupDao;
    @Autowired
    private TeacherDefaultVipGroupSalaryDao teacherDefaultVipGroupSalaryDao;
    @Autowired
    private ClassGroupTeacherMapperService classGroupTeacherMapperService;
    @Autowired
    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private ClassGroupService classGroupService;
    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private ClassGroupTeacherSalaryDao classGroupTeacherSalaryDao;
    @Autowired
    private JiaRiFeignService jiaRiFeignService;
    @Autowired
    private VipGroupService vipGroupService;
    @Autowired
    private MusicGroupService musicGroupService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private GroupDao groupDao;
    @Autowired
    private TeacherDao teacherDao;

    private final Logger LOGGER = LoggerFactory
            .getLogger(this.getClass());

    @Override
    public BaseDAO<Long, CourseSchedule> getDAO() {
        return courseScheduleDao;
    }

    @Override
    public TeacherAttendanceDto getCurrentCourseDetail(Long courseID) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        if (Objects.isNull(courseID)) {
            throw new BizException("参数错误!");
        }
        TeacherAttendanceDto currentCourseDetail = courseScheduleDao.getCurrentCourseDetail(courseID, user.getId());
        if (Objects.isNull(currentCourseDetail)) {
            throw new BizException("课程不存在");
        }
        if(Objects.nonNull(currentCourseDetail.getSchoolId())){
            YesOrNoEnum yesOrNoEnum = enableOnlyNormalAttendance(currentCourseDetail.getStartClassTime(),
                    user.getId().longValue(),
                    true,
                    currentCourseDetail.getSchoolId().intValue());
            currentCourseDetail.setOnlyNormal(yesOrNoEnum);
        }else{
            currentCourseDetail.setOnlyNormal(YesOrNoEnum.NO);
        }

        currentCourseDetail.setCurrentClassTimes(courseScheduleDao.countClassGroupOverCourseNum(currentCourseDetail.getClassId()));
        SysConfig sysConfig = sysConfigService.findByParamName(SysConfigService.ENABLE_STUDENT_ATTENDANCE_TIME_RANGE);
        SysConfig sysConfigVip = sysConfigService.findByParamName(SysConfigService.ENABLE_STUDENT_ATTENDANCE_TIME_RANGE_VIP);
        currentCourseDetail.setEnableStudentAttendanceTimeRange(sysConfig.getParanValue(Integer.class));
        currentCourseDetail.setEnableStudentAttendanceTimeRange(sysConfigVip.getParanValue(Integer.class));
        int studentNum = studentAttendanceDao.countByCourseSchedule(courseID);
        if (Objects.nonNull(studentNum)) {
            currentCourseDetail.setStudentAttendanceIsFirstTime(studentNum > 0 ? 0 : 1);
        } else {
            currentCourseDetail.setStudentAttendanceIsFirstTime(1);
        }

        currentCourseDetail.setCurrentTime(new Date());
        currentCourseDetail.setAdvanceSignInMinutes(Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_SIGN_IN_MINUTES)));
        currentCourseDetail.setAttendanceRange(Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ATTENDANCE_RANGE)));
        return currentCourseDetail;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCourseSchedules(List<Long> courseScheduleIds) {
        Integer classGroupId = null;
        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleIds.get(0));
            if(Objects.nonNull(courseSchedule)){
                classGroupId = courseSchedule.getClassGroupId();
            }
        }
        List<Long> enableDeleteIds = courseScheduleDao.filterNotStartCourseIdsWithIds(courseScheduleIds);
        if (!CollectionUtils.isEmpty(enableDeleteIds)) {
            courseScheduleDao.batchDeleteCourseSchedules(enableDeleteIds);
            courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(enableDeleteIds);
            courseScheduleStudentPaymentDao.deleteByCourseSchedule(enableDeleteIds);
            teacherAttendanceDao.batchDeleteByCourseSchedules(enableDeleteIds);
            if (Objects.nonNull(classGroupId)) {
                classGroupService.updateClassGroupInfo(classGroupId);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteMusicGroupNotStartCourse(String musicGroupId, GroupType groupType) {
        if (StringUtils.isBlank(musicGroupId)) {
            throw new BizException("请指定乐团");
        }
        List<CourseSchedule> musicGroupCourseSchedules = courseScheduleDao.findMusicGroupCourseSchedules(musicGroupId, groupType.getCode(), CourseStatusEnum.NOT_START.getCode());
        if (CollectionUtils.isEmpty(musicGroupCourseSchedules)) {
            throw new BizException("此乐团不存在未上课程");
        }
        List<Long> courseScheduleIds = musicGroupCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());
        deleteCourseSchedules(courseScheduleIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDeleteMusicGroupCourseWithStudent(String musicGroupId, Integer userId, GroupType groupType) {
        if (StringUtils.isBlank(musicGroupId)) {
            throw new BizException("请指定乐团");
        }
        List<CourseSchedule> musicGroupCourseSchedules = courseScheduleDao.findMusicGroupCourseSchedulesWithStudent(musicGroupId, groupType.getCode(), CourseStatusEnum.NOT_START.getCode(), userId);
        if (!CollectionUtils.isEmpty(musicGroupCourseSchedules)) {
            List<Long> courseScheduleIds = musicGroupCourseSchedules.stream()
                    .map(courseSchedule -> courseSchedule.getId())
                    .collect(Collectors.toList());
            courseScheduleDao.deleteMusicGroupCourseSchedulesWithStudent(courseScheduleIds, userId);
        }
    }

    @Override
    public YesOrNoEnum enableOnlyNormalAttendance(Date startClassTime, Long userId, boolean checkSchool, Integer schoolId) {
        Date endTime = startClassTime;
        Date startTime = DateUtil.addHours(endTime, -1);
        List<TeacherAttendanceDto> teacherCourseByDateSpeeds = courseScheduleDao.getTeacherCourseByDateSpeed(startTime, endTime, userId, schoolId);
        if (CollectionUtils.isEmpty(teacherCourseByDateSpeeds)) {
            return YesOrNoEnum.NO;
        } else {
            if (checkSchool
                    && Objects.nonNull(schoolId)) {
                return YesOrNoEnum.YES;
            } else {
                return YesOrNoEnum.NO;
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createCourseSchedules(CreateCourseScheduleDto createCourseScheduleDto) {
        List<CourseSchedule> courseSchedules = createCourseScheduleDto.getCourseSchedules();

        if(!CollectionUtils.isEmpty(courseSchedules)){
            //添加课程计划
            batchAddCourseSchedule(courseSchedules);
            //更新课次
            List<Integer> classGroupIds = courseSchedules.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
            classGroupService.batchUpdateClassCourseTimes(classGroupIds);
            //创建学生单节课的缴费记录，乐团课的缴费为0
            courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentByCourseSchedules(courseSchedules);
        }

        MusicGroup musicGroup = musicGroupService.get(createCourseScheduleDto.getMusicGroupID());

        if (musicGroup.getStatus().equals(MusicGroupStatusEnum.PROGRESS)) {
            classGroupTeacherMapperService.createMusicGroupTeacherMapper(createCourseScheduleDto.getCourseSchedules(), musicGroup.getId());
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAddCourseSchedule(List<CourseSchedule> courseSchedules) {
        if (Objects.isNull(courseSchedules) && courseSchedules.size() <= 0) {
            throw new BizException("参数错误!");
        }
        checkNewCourseSchedules(courseSchedules, false);
        createCourseScheduleName(courseSchedules);
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdateCourseSchedule(List<CourseSchedule> courseSchedules, String musicGroupID) {
        if (Objects.isNull(courseSchedules) && courseSchedules.size() <= 0) {
            throw new BizException("请选择需要调整的课程!");
        }
        if (Objects.isNull(musicGroupID)) {
            throw new BizException("请指定乐团!");
        }
        checkNewCourseSchedules(courseSchedules, false);
        courseScheduleDao.deleteCourseSchedulesByMusicGroupID(musicGroupID, GroupType.MUSIC);
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
    }

    @Override
    public List<Date> getCourseScheduleDateByMonth(Long musicGroupID, Date month) {
        if (Objects.isNull(month) || Objects.isNull(musicGroupID)) {
            throw new BizException("请选择日期并指定乐团!");
        }
        return courseScheduleDao.getCourseScheduleDateByMonth(musicGroupID, month);
    }

    @Override
    public List<Date> getCourseScheduleDateByStudent(Date month, Integer isAttend) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        return courseScheduleDao.getStudentCourseScheduleDate(user.getId().longValue(), month, isAttend);
    }

    @Override
    public List<Date> getCourseScheduleDateByTeacher(Date month, String type) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("获取用户信息失败");
        }
        return courseScheduleDao.getTeacherCourseScheduleDate(user.getId().longValue(), month, type);
    }

    @Override
    public List<Date> getHistoryCourseScheduleDateByTeacher(Integer userId, Date month) {
        return courseScheduleDao.getTeacherHistoryCourseScheduleDate(userId, month);
    }

    @Override
    public List<Date> getCourseScheduleDates(Date month, String organIdList, String type) {
        return courseScheduleDao.getCourseScheduleDate(month, organIdList,type);
    }

    @Override
    public Map getStudentCourseSchedulesWithDate(Date classDate) {
        if (Objects.isNull(classDate)) {
            throw new BizException("请选择上课日期!");
        }
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("请登录");
        }
        Date now = new Date();
        SysConfig studentAttendanceAfterTimeConfig = sysConfigService.findByParamName(SysConfigService.ENABLE_STUDENT_ATTENDANCE_BEFOR_COURSE_START_TIME_RANGE_VIP);
        Map<String, Object> result = new HashMap<>(3);
        result.put("vipAppealDaysRange", sysConfigDao.findConfigValue(SysConfigService.VIP_APPEAL_DAYS_RANGE));
        result.put("advanceLeaveHours", Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.ADVANCE_LEAVE_HOURS)));
        result.put("joinRoomBeforeTime",studentAttendanceAfterTimeConfig.getParanValue(Integer.class));
//		List<Integer> quitClassGroupIds=classGroupStudentMapperDao.findClassGroupIdByUserAndCourseDateAndStatus(user.getId(),classDate, ClassGroupStudentStatusEnum.QUIT.getCode());
        List<CourseScheduleDto> studentCourseSchedulesWithDate = courseScheduleDao.getStudentCourseSchedulesWithDate(classDate, user.getId().longValue(), null);
        List<Long> courseScheduleIds = studentCourseSchedulesWithDate.stream()
                .filter(cs -> cs.getType().equals(CourseSchedule.CourseScheduleType.VIP) || cs.getType().equals(CourseSchedule.CourseScheduleType.DEMO))
                .map(CourseScheduleDto::getId).collect(Collectors.toList());

        Map<Integer, String> subjectNameCourseMap = new HashMap<>();
        Map<Integer, String> subjectIdCourseMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            List<Map<Integer, String>> subjectNameCourseMaps = subjectDao.findSubjectNameCourseMaps(courseScheduleIds);
            List<Map<Integer, String>> subjectIdCourseMaps = subjectDao.findClassGroupSubjectId(courseScheduleIds);
            subjectNameCourseMap = MapUtil.convertMybatisMap(subjectNameCourseMaps);
            subjectIdCourseMap = MapUtil.convertMybatisMap(subjectIdCourseMaps);
        }

        for (CourseScheduleDto courseScheduleDto : studentCourseSchedulesWithDate) {
            if (now.before(courseScheduleDto.getStartClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.NOT_START);
            } else if (now.after(courseScheduleDto.getEndClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.OVER);
            } else {
                courseScheduleDto.setStatus(CourseStatusEnum.UNDERWAY);
            }
            courseScheduleDto.setSubjectName(subjectNameCourseMap.get(courseScheduleDto.getId()));
            courseScheduleDto.setSubjectId(subjectIdCourseMap.get(courseScheduleDto.getId()));
        }
        result.put("list", studentCourseSchedulesWithDate);
        return result;
    }

    @Override
    public PageInfo getCourseSchedulesWithDateByEdu(CourseScheduleQueryInfo queryInfo) {
//        queryInfo.setOrganId(Long.parseLong(user.getOrganId()));
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (Objects.isNull(queryInfo.getDate())) {
            queryInfo.setDate(new Date());
        }

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

        params.put("musicGroupStatus", null);
        params.put("vipGroupStatus", null);
        List<Group> groups = groupDao.searchGroups(params);
        if(!CollectionUtils.isEmpty(groups)){
            params.put("groups", groups);
        }else{
            return pageInfo;
        }

        List<CourseScheduleDto> dataList = null;
        int count = courseScheduleDao.countCourseSchedulesWithDate(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = courseScheduleDao.getCourseSchedulesWithDate(params);
            List<Long> allCourseScheduleIds = dataList.stream().map(CourseScheduleDto::getId).collect(Collectors.toList());
            List<Map<Integer, Integer>> courseStudentNumMaps = courseScheduleStudentPaymentDao.countCourseStudentNum(allCourseScheduleIds);
            Map<Long, Long> courseStudentNumMap = MapUtil.convertIntegerMap(courseStudentNumMaps);

            List<Group> groupsT=new ArrayList<>();
            groupsT.add(null);
            List<Integer> teacherIds=new ArrayList<>();
            for (CourseScheduleDto courseScheduleEndDto : dataList) {
                Group group=new Group(courseScheduleEndDto.getMusicGroupId(),courseScheduleEndDto.getGroupType());
                groupsT.add(group);
                teacherIds.add(courseScheduleEndDto.getActualTeacherId());
            }
            groupsT = groupDao.findByGroupIds(groupsT);
            Map<String, Group> idGroupMap = groupsT.stream().collect(Collectors.toMap(Group::getId, group -> group));

            for (int i=0;i<dataList.size();i++) {
                Long studentNum=courseStudentNumMap.get(dataList.get(i).getId());
                dataList.get(i).setTotalStudentNum(Objects.isNull(studentNum)?0:studentNum.intValue());
                Group group = idGroupMap.get(dataList.get(i).getMusicGroupId());
                if(Objects.nonNull(group)){
                    dataList.get(i).setGroupName(group.getGroupName());
                }
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public List<CourseScheduleDto> getTeacherCourseSchedulesWithDate(Integer userId, Date classDate, String type) {
        if (Objects.isNull(classDate)) {
            throw new BizException("请选择上课日期!");
        }
        Date now = new Date();
        List<CourseScheduleDto> teacherCourseSchedulesWithDate = courseScheduleDao.getTeacherCourseSchedulesWithDate(classDate, userId.longValue(), type);
        List<Long> allCourseScheduleIds = teacherCourseSchedulesWithDate.stream().map(CourseScheduleDto::getId).collect(Collectors.toList());
        List<Long> courseScheduleIds = teacherCourseSchedulesWithDate.stream()
                .filter(cs -> cs.getType().equals(CourseSchedule.CourseScheduleType.VIP) ||
                        cs.getType().equals(CourseSchedule.CourseScheduleType.DEMO) ||
                        cs.getType().equals(CourseSchedule.CourseScheduleType.PRACTICE))
                .map(CourseScheduleDto::getId).collect(Collectors.toList());

        Map<Integer, String> subjectNameCourseMap = new HashMap<>();
        Map<Integer, String> subjectIdCourseMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            List<Map<Integer, String>> subjectNameCourseMaps = subjectDao.findSubjectNameCourseMaps(courseScheduleIds);
            List<Map<Integer, String>> subjectIdCourseMaps = subjectDao.findClassGroupSubjectId(courseScheduleIds);
            subjectNameCourseMap = MapUtil.convertMybatisMap(subjectNameCourseMaps);
            subjectIdCourseMap = MapUtil.convertMybatisMap(subjectIdCourseMaps);
        }
        List<Map<Integer, Integer>> studentNumCourseMaps = null;
        if (!CollectionUtils.isEmpty(allCourseScheduleIds)) {
            studentNumCourseMaps = studentAttendanceDao.countStudentAttendancesByCourses(allCourseScheduleIds);
        }
        Map<Integer, Long> studentNumCourseMap = new HashMap<>();
        if (Objects.nonNull(studentNumCourseMaps)) {
            studentNumCourseMap = MapUtil.convertIntegerMap(studentNumCourseMaps);
        }

        if(CollectionUtils.isEmpty(teacherCourseSchedulesWithDate)){
            return teacherCourseSchedulesWithDate;
        }

        List<Integer> classGroupIds = teacherCourseSchedulesWithDate.stream().map(CourseScheduleDto::getClassGroupId).collect(Collectors.toList());
        List<Map<Integer, Integer>> classGroupStudentNumMaps = classGroupStudentMapperDao.countClassGroupsStudentNum(classGroupIds, ClassGroupStudentStatusEnum.NORMAL);
        Map<Integer, Long> classGroupStudentNumMap = MapUtil.convertIntegerMap(classGroupStudentNumMaps);

        SysConfig advanceLeaveHoursConfig = sysConfigService.findByParamName(SysConfigService.ADVANCE_LEAVE_HOURS);
        Integer advanceLeaveHours=advanceLeaveHoursConfig.getParanValue(Integer.class);
        List<Map<Long, Integer>> courseLeaveStudentNumMaps = studentAttendanceDao.countCourseLeaveStudentNumWithFourHoursAgo(allCourseScheduleIds, advanceLeaveHours);
        Map<Long,Long> courseLeaveStudentNumMap = MapUtil.convertIntegerMap((courseLeaveStudentNumMaps));

        for (CourseScheduleDto courseScheduleDto : teacherCourseSchedulesWithDate) {
            Long studentNum = studentNumCourseMap.get(courseScheduleDto.getId());
            if (Objects.nonNull(studentNum)) {
                courseScheduleDto.setStudentAttendanceIsFirstTime(studentNum > 0 ? 0 : 1);
            } else {
                courseScheduleDto.setStudentAttendanceIsFirstTime(1);
            }

            if (now.before(courseScheduleDto.getStartClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.NOT_START);
            } else if (now.after(courseScheduleDto.getEndClassTime())) {
                courseScheduleDto.setStatus(CourseStatusEnum.OVER);
            } else {
                courseScheduleDto.setStatus(CourseStatusEnum.UNDERWAY);
            }
            if (Objects.nonNull(courseScheduleDto.getClassGroupId())) {
                String[] studentNames = classGroupStudentMapperDao.findCourseStudentName(courseScheduleDto.getId().intValue());
                courseScheduleDto.setStudentNames(org.apache.commons.lang3.StringUtils.join(studentNames, ","));
            }
            courseScheduleDto.setSubjectName(subjectNameCourseMap.get(courseScheduleDto.getId()));
            courseScheduleDto.setSubjectId(subjectIdCourseMap.get(courseScheduleDto.getId()));
            Long leaveStudentNum = courseLeaveStudentNumMap.get(courseScheduleDto.getId());
            Long normalStudentNum = classGroupStudentNumMap.get(courseScheduleDto.getClassGroupId());
            if(Objects.nonNull(leaveStudentNum)&&Objects.nonNull(normalStudentNum)&&leaveStudentNum.intValue()==normalStudentNum.intValue()){
                courseScheduleDto.setEnableAdjustInToday(1);
            }
        }
        return teacherCourseSchedulesWithDate;
    }

    @Override
    public List<CourseScheduleDto> getTeacherHistoryCourseSchedulesWithDate(Integer userId, Date classDate) {
        if (Objects.isNull(classDate)) {
            throw new BizException("请选择上课日期!");
        }
        List<CourseScheduleDto> teacherCourseSchedulesWithDate = courseScheduleDao.getTeacherHistoryCourseSchedulesWithDate(classDate, userId.longValue());
        List<Long> courseScheduleIds = teacherCourseSchedulesWithDate.stream()
                .filter(cs -> cs.getType().equals(CourseSchedule.CourseScheduleType.VIP) || cs.getType().equals(CourseSchedule.CourseScheduleType.DEMO))
                .map(CourseScheduleDto::getId).collect(Collectors.toList());

        Map<Integer, String> subjectNameCourseMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(courseScheduleIds)) {
            List<Map<Integer, String>> subjectNameCourseMaps = subjectDao.findSubjectNameCourseMaps(courseScheduleIds);
            subjectNameCourseMap = MapUtil.convertMybatisMap(subjectNameCourseMaps);
        }
        for (CourseScheduleDto courseScheduleDto : teacherCourseSchedulesWithDate) {
            if (Objects.nonNull(courseScheduleDto.getClassGroupId())) {
                String[] studentNums = classGroupStudentMapperDao.findCourseStudentName(courseScheduleDto.getId().intValue());
                courseScheduleDto.setStudentNames(org.apache.commons.lang3.StringUtils.join(studentNums, ","));
            }
            courseScheduleDto.setSubjectName(subjectNameCourseMap.get(courseScheduleDto.getId()));
        }
        return teacherCourseSchedulesWithDate;
    }

    @Override
    public void checkNewCourseSchedules(List<CourseSchedule> courseSchedules, boolean checkExistCourseSchedule) {
        if (CollectionUtils.isEmpty(courseSchedules)) {
            return;
        }
        List<String> classDates = courseSchedules.stream().map(courseSchedule -> DateUtil.dateToString(courseSchedule.getClassDate(), "yyyy-MM-dd"))
                .collect(Collectors.toList());

        List<CourseSchedule> existCourseSchedules = courseScheduleDao.findByClassDate(classDates);

        //只需要调整课程信息的课程编号列表
        List<Long> updateCourseScheduleIds = courseSchedules
                .stream()
                .filter(courseSchedule -> Objects.nonNull(courseSchedule.getId()))
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //排除只需调整的课程
        existCourseSchedules = existCourseSchedules.stream()
                .filter(courseSchedule -> !updateCourseScheduleIds.contains(courseSchedule.getId()))
                .collect(Collectors.toList());
        //新课程对应的班级编号列表
        List<Integer> newCourseScheduleClassGroupIds = courseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());

        List<Long> existCourseScheduleIds = existCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        HashSet<Long> courseScheduleIdsSet = new HashSet<>(existCourseScheduleIds);

        //合并新课程和已存在的课程
        List<CourseSchedule> allCourseSchedules;
        if (!CollectionUtils.isEmpty(existCourseSchedules)) {
            allCourseSchedules = ListUtils.sum(courseSchedules, existCourseSchedules);
        } else {
            allCourseSchedules = courseSchedules;
        }
        //所有课程的班级编号
        List<Integer> classGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());
        //班级与学生的关联记录
        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
        Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentMappers
                .stream()
                .collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));

        //根据课程获取助教id关联集合
        List<IntegerAndIntegerListDto> courseScheduleTeachingTeacherIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(existCourseScheduleIds)) {
            courseScheduleTeachingTeacherIdList = courseScheduleDao.findCourseScheduleIdAndUserIdsMap(existCourseScheduleIds, TeachTypeEnum.TEACHING.getCode());
        }
        Map<Integer, IntegerAndIntegerListDto> courseScheduleTeachingTeacherMap = courseScheduleTeachingTeacherIdList.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        //班级助教关联ID集合
        List<IntegerAndIntegerListDto> classGroupAndUserIdsMap = courseScheduleDao.findClassGroupAndUserIdsMap(newCourseScheduleClassGroupIds, TeachTypeEnum.TEACHING.getCode());
        Map<Integer, IntegerAndIntegerListDto> classGroupTeachingTeacherMap = classGroupAndUserIdsMap.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        //将课程计划按照开课时间排序
        allCourseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
        if (allCourseSchedules.size() > 1) {
            //记录连续冲突的次数
            int repeatTimes = 1;
            for (int i = 1; i < allCourseSchedules.size(); i++) {
                int temp_repeat = repeatTimes;
                for (int j = 1; j <= temp_repeat; j++) {
                    //当前课程
                    CourseSchedule preCourseSchedule = allCourseSchedules.get(i - j);
                    //后面一节课程
                    CourseSchedule backCourseSchedule = allCourseSchedules.get(i);
                    //判断前后两节课是否存在冲突
                    if (backCourseSchedule.getStartClassTime().before(preCourseSchedule.getEndClassTime())) {
                        if (j == repeatTimes) {
                            repeatTimes += 1;
                        }
                        if (!checkExistCourseSchedule
                                && courseScheduleIdsSet.contains(preCourseSchedule.getId())
                                && courseScheduleIdsSet.contains(backCourseSchedule.getId())) {
                            continue;
                        }

                        //如果存在时间重叠，则需要判断前后两节课的教师和学生是否存在冲突
                        //主教冲突检测
                        if (Objects.nonNull(preCourseSchedule.getActualTeacherId())
                                && preCourseSchedule.getActualTeacherId().equals(backCourseSchedule.getActualTeacherId())) {

                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 1));
                        }
                        //助教冲突检测
                        if (Objects.isNull(preCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(preCourseSchedule.getClassGroupId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                preCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        } else if (existCourseScheduleIds.contains(preCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(preCourseSchedule.getId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                preCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        }
                        if (Objects.isNull(backCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = classGroupTeachingTeacherMap.get(backCourseSchedule.getClassGroupId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                backCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        } else if (existCourseScheduleIds.contains(backCourseSchedule.getId())) {
                            IntegerAndIntegerListDto integerAndIntegerListDto = courseScheduleTeachingTeacherMap.get(backCourseSchedule.getId());
                            if (Objects.nonNull(integerAndIntegerListDto)) {
                                backCourseSchedule.setTeachingTeacherIdList(integerAndIntegerListDto.getIds());
                            }
                        }
                        if (!CollectionUtils.isEmpty(preCourseSchedule.getTeachingTeacherIdList())
                                && !CollectionUtils.isEmpty(backCourseSchedule.getTeachingTeacherIdList())) {
                            List<Integer> repeatIds = preCourseSchedule.getTeachingTeacherIdList()
                                    .stream().filter(backCourseSchedule.getTeachingTeacherIdList()::contains)
                                    .collect(Collectors.toList());
                            if (!CollectionUtils.isEmpty(repeatIds)) {
                                throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 2));
                            }
                        }
                        //学生冲突检测
                        if (preCourseSchedule.getClassGroupId().equals(backCourseSchedule.getClassGroupId())) {
                            //如果班级相同，则学生肯定存在冲突
                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
                        }
                        //如果班级不同，则需要检测两个班级是否存在重复的学生
                        List<ClassGroupStudentMapper> preClassGroupStudents = classGroupStudentsMap.get(preCourseSchedule.getClassGroupId());
                        List<ClassGroupStudentMapper> backClassGroupStudents = classGroupStudentsMap.get(backCourseSchedule.getClassGroupId());
                        //如果有一个存在没有学生的班级则不存在冲突
                        if (CollectionUtils.isEmpty(preClassGroupStudents) || CollectionUtils.isEmpty(backClassGroupStudents)) {
                            continue;
                        }
                        //当前课程所在班级的学生编号列表
                        List<Integer> preClassGroupStudentIds = preClassGroupStudents.stream()
                                .map(ClassGroupStudentMapper::getUserId)
                                .collect(Collectors.toList());
                        //后面一节课程所在班级的学生编号列表
                        List<Integer> backClassGroupStudentIds = backClassGroupStudents.stream()
                                .map(ClassGroupStudentMapper::getUserId)
                                .collect(Collectors.toList());
                        List<Integer> repeatStudentIds = preClassGroupStudentIds.stream()
                                .filter(backClassGroupStudentIds::contains)
                                .collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(repeatStudentIds)) {
                            throw new BizException(courseCheckInfo(preCourseSchedule, backCourseSchedule, existCourseScheduleIds, 3));
                        }
                    } else {
                        repeatTimes = j;
                        break;
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> checkSnapCourseShchedules(List<CourseSchedule> courseSchedules) {
        List<Long> courseScheduleIds = new ArrayList<>();
        List<CourseScheduleStudentDto> courseScheduleStudents = new ArrayList<>();
        if (CollectionUtils.isEmpty(courseSchedules)) {
            return courseScheduleIds;
        }
        //第一节课
        CourseSchedule firstCourseSchedule;
        //最后一节课
        CourseSchedule latestCourseSchedule;
        if (courseSchedules.size() == 1) {
            firstCourseSchedule = courseSchedules.get(0);
            latestCourseSchedule = courseSchedules.get(0);
        } else {
            firstCourseSchedule = courseSchedules.stream().min(Comparator.comparing(CourseSchedule::getStartClassTime)).get();
            latestCourseSchedule = courseSchedules.stream().max(Comparator.comparing(CourseSchedule::getEndClassTime)).get();
        }
        //获取第一节课和最后一节课所包含的时间段内已存在的课程
        List<CourseSchedule> existCourseSchedules = courseScheduleDao
                .findAllCourseByDateZone(firstCourseSchedule.getStartClassTime(), latestCourseSchedule.getEndClassTime());

        if (existCourseSchedules == null || existCourseSchedules.size() == 0) {
            return null;
        }
        //只需要调整课程信息的课程编号列表
        List<Long> updateCourseScheduleIds = courseSchedules
                .stream()
                .filter(courseSchedule -> Objects.nonNull(courseSchedule.getId()))
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //排除只需调整的课程
        existCourseSchedules = existCourseSchedules.stream()
                .filter(courseSchedule -> !updateCourseScheduleIds.contains(courseSchedule.getId()))
                .collect(Collectors.toList());
        if (existCourseSchedules == null || existCourseSchedules.size() == 0) {
            return null;
        }


        List<Long> existCourseScheduleIds = existCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .collect(Collectors.toList());

        //合并新课程和已存在的课程
        List<CourseSchedule> allCourseSchedules;
        if (!CollectionUtils.isEmpty(existCourseSchedules)) {
            allCourseSchedules = ListUtils.sum(courseSchedules, existCourseSchedules);
        } else {
            allCourseSchedules = courseSchedules;
        }

        //新课程对应的班级编号列表
        List<Integer> newCourseScheduleClassGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());

        //所有课程的班级编号
        List<Integer> classGroupIds = allCourseSchedules
                .stream()
                .map(CourseSchedule::getClassGroupId)
                .distinct()
                .collect(Collectors.toList());
        //班级与学生的关联记录
        List<CourseScheduleStudentPayment> exitStudentPaymentList = courseScheduleStudentPaymentDao.findByCourseScheduleIds(existCourseScheduleIds);

        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIds);
        Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentMappers
                .stream()
                .collect(Collectors.groupingBy(ClassGroupStudentMapper::getClassGroupId));

        Map<Long, List<CourseScheduleStudentPayment>> exitStudentPaymentMap = exitStudentPaymentList.stream().collect(Collectors.groupingBy(CourseScheduleStudentPayment::getCourseScheduleId));

        //根据课程获取教师id关联集合
        List<IntegerAndIntegerListDto> courseScheduleTeachingTeacherIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(existCourseScheduleIds)) {
            courseScheduleTeachingTeacherIdList = courseScheduleDao.findCourseScheduleIdAndUserIdsMap(existCourseScheduleIds, null);
        }
        Map<Integer, IntegerAndIntegerListDto> courseScheduleTeacherMap = courseScheduleTeachingTeacherIdList.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        //班级教师关联ID集合
        List<IntegerAndIntegerListDto> classGroupAndUserIdsMap = courseScheduleDao.findClassGroupAndUserIdsMap(newCourseScheduleClassGroupIds, null);
        Map<Integer, IntegerAndIntegerListDto> classGroupTeachingTeacherMap = classGroupAndUserIdsMap.stream()
                .collect(Collectors.toMap(IntegerAndIntegerListDto::getId, integerAndIntegerListDto -> integerAndIntegerListDto));

        existCourseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));
        courseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        newNode:
        for (CourseSchedule newCourseSchedule : courseSchedules) {
            for (CourseSchedule existCourseSchedule : existCourseSchedules) {
                if (newCourseSchedule.getEndClassTime().compareTo(existCourseSchedule.getStartClassTime()) <= 0) {
                    continue newNode;
                }
                if (existCourseSchedule.getEndClassTime().compareTo(newCourseSchedule.getStartClassTime()) <= 0) {
                    continue;
                }

                boolean isTeacherRepeat = false;
                boolean isStudentRepeat = false;
                //检测老师冲突
                if (courseScheduleTeacherMap.containsKey(existCourseSchedule.getId().intValue())) {
                    existCourseSchedule.setTeachingTeacherIdList(courseScheduleTeacherMap.get(existCourseSchedule.getId().intValue()).getIds());
                } else {
                    existCourseSchedule.setTeachingTeacherIdList(classGroupTeachingTeacherMap.get(existCourseSchedule.getClassGroupId()).getIds());
                }
                newCourseSchedule.setTeachingTeacherIdList(classGroupTeachingTeacherMap.get(newCourseSchedule.getClassGroupId()).getIds());

                if (!CollectionUtils.isEmpty(newCourseSchedule.getTeachingTeacherIdList())
                        && !CollectionUtils.isEmpty(existCourseSchedule.getTeachingTeacherIdList())) {
                    List<Integer> repeatIds = newCourseSchedule.getTeachingTeacherIdList()
                            .stream().filter(existCourseSchedule.getTeachingTeacherIdList()::contains)
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(repeatIds)) {
                        isTeacherRepeat = true;
                    }
                }

                //学生冲突检测
                if (newCourseSchedule.getClassGroupId().equals(existCourseSchedule.getClassGroupId())) {
                    //如果班级相同，则学生肯定全部存在冲突，当做老师冲突处理
                    isTeacherRepeat = true;
                }

                List<Integer> repeatStudentIds = new ArrayList<>();
                if (!isTeacherRepeat && classGroupStudentsMap.containsKey(newCourseSchedule.getClassGroupId()) && exitStudentPaymentMap.containsKey(existCourseSchedule.getId())) {
                    //如果班级不同，则需要检测两个班级是否存在重复的学生
                    List<ClassGroupStudentMapper> preClassGroupStudents = classGroupStudentsMap.get(newCourseSchedule.getClassGroupId());
                    List<CourseScheduleStudentPayment> backClassGroupStudents = exitStudentPaymentMap.get(existCourseSchedule.getId());

                    //当前课程所在班级的学生编号列表
                    List<Integer> preClassGroupStudentIds = preClassGroupStudents.stream()
                            .map(ClassGroupStudentMapper::getUserId)
                            .collect(Collectors.toList());
                    //后面一节课程所在班级的学生编号列表
                    List<Integer> backClassGroupStudentIds = backClassGroupStudents.stream()
                            .map(CourseScheduleStudentPayment::getUserId)
                            .collect(Collectors.toList());
                    repeatStudentIds = preClassGroupStudentIds.stream()
                            .filter(backClassGroupStudentIds::contains)
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(repeatStudentIds)) {
                        isStudentRepeat = true;
                    }

                    if(isStudentRepeat && (backClassGroupStudentIds.size() == repeatStudentIds.size())){
                        isStudentRepeat = false;
                        isTeacherRepeat = true;
                    }
                }

                if (!isTeacherRepeat && !isStudentRepeat) {
                    continue;
                }

                if (existCourseSchedule.getClassGroupType().equals(ClassGroupTypeEnum.SNAP.getCode()) || existCourseSchedule.getClassGroupType().equals(ClassGroupTypeEnum.VIP.getCode())) {
                    throw new BizException(courseCheckInfo(newCourseSchedule, existCourseSchedule, existCourseScheduleIds, 1));
                }

                if (!existCourseSchedule.getGroupType().equals(newCourseSchedule.getGroupType()) || !existCourseSchedule.getMusicGroupId().equals(newCourseSchedule.getMusicGroupId())) {
                    throw new BizException(courseCheckInfo(newCourseSchedule, existCourseSchedule, existCourseScheduleIds, 1));
                }

                if (isTeacherRepeat) {
                    courseScheduleIds.add(existCourseSchedule.getId());
                }
                if (isStudentRepeat) {
                    CourseScheduleStudentDto courseScheduleStudentDto = new CourseScheduleStudentDto();
                    courseScheduleStudentDto.setId(existCourseSchedule.getId());
                    courseScheduleStudentDto.setStudentIds(repeatStudentIds);
                    courseScheduleStudents.add(courseScheduleStudentDto);
                }

            }
        }
        //老师冲突删除课程课程
        if (courseScheduleIds.size() > 0) {
            courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
            courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
            teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
            courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
        }
        //学生冲突删除学生课程
        if (courseScheduleStudents.size() > 0) {
            for (CourseScheduleStudentDto courseScheduleStudent : courseScheduleStudents) {
                courseScheduleStudentPaymentDao.deleteStudentCourseScheduleByUserId(courseScheduleStudent.getId(), courseScheduleStudent.getStudentIds());
            }
        }
        return courseScheduleIds;
    }

    private String courseCheckInfo(CourseSchedule preCourseSchedule, CourseSchedule backCourseSchedule, List<Long> existCourseScheduleIds, Integer type) {
        //提示信息
        StringBuffer errInfo = new StringBuffer("在");
        errInfo.append(DateUtil.dateToString(preCourseSchedule.getStartClassTime(), "yyyy-MM-dd HH:mm"));
        errInfo.append("至");
        errInfo.append(DateUtil.dateToString(backCourseSchedule.getEndClassTime(), "yyyy-MM-dd HH:mm"));
        errInfo.append("的时间段内");
        errInfo.append("安排的课程存在冲突,");
        errInfo.append("冲突课程为：");

        if (Objects.isNull(preCourseSchedule.getId()) && Objects.isNull(backCourseSchedule.getId())) {
            errInfo.setLength(0);
            errInfo.append("您设置的循环周期存在时间冲突");
            return errInfo.toString();
        }

        CourseSchedule courseSchedule = new CourseSchedule();
        if (Objects.nonNull(preCourseSchedule.getId()) && existCourseScheduleIds.contains(preCourseSchedule.getId())) {
            courseSchedule = preCourseSchedule;
        }
        if (Objects.nonNull(backCourseSchedule.getId()) && existCourseScheduleIds.contains(backCourseSchedule.getId())) {
            courseSchedule = backCourseSchedule;
        }

        String groupName = "";

        if (Objects.nonNull(courseSchedule.getId())) {
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.VIP)) {
                VipGroup vipGroup = vipGroupDao.get(Long.valueOf(courseSchedule.getMusicGroupId()));
                if (Objects.nonNull(vipGroup)) {
                    groupName = vipGroup.getName();
                }
            } else {
                MusicGroup musicGroup = musicGroupDao.get(courseSchedule.getMusicGroupId());
                if (Objects.nonNull(musicGroup)) {
                    groupName = musicGroup.getName();
                }
            }
        }

        errInfo.append(groupName);
        errInfo.append("(");
        errInfo.append(courseSchedule.getMusicGroupId());
        errInfo.append(")-");
        errInfo.append(courseSchedule.getName());
        errInfo.append("(");
        errInfo.append(courseSchedule.getId());
        errInfo.append(")");

        errInfo.append("类型为：");
        switch (type) {
            case 1:
                errInfo.append("主教冲突");
                break;
            case 2:
                errInfo.append("助教冲突");
                break;
            case 3:
                errInfo.append("学生冲突");
                break;
            default:
                errInfo.append("未知冲突");
                break;
        }

        return errInfo.toString();
    }

    /**
     * 判断课程安排中是否存在冲突
     * 计算课程课次
     *
     * @param courseSchedules
     * @return
     */
    private void checkCourseSchedule(List<CourseSchedule> courseSchedules) {
        List<Date> classDates = courseSchedules.stream().map(CourseSchedule::getClassDate).collect(Collectors.toList());
        List<CourseSchedule> byClassGroupAndDate = courseScheduleDao.findByClassGroupAndDate(classDates, null);
        List<CourseSchedule> collect3 = Stream.of(courseSchedules, byClassGroupAndDate).flatMap(Collection::stream).collect(Collectors.toList());
        Map<Date, List<CourseSchedule>> collect = collect3.stream().collect(Collectors.groupingBy(CourseSchedule::getClassDate));
        for (Date keyDate : collect.keySet()) {
            List<CourseSchedule> currentCourses = collect.get(keyDate);
            Map<Date, List<CourseSchedule>> collect1 = currentCourses.stream().collect(Collectors.groupingBy(CourseSchedule::getStartClassTime));
            if (currentCourses.size() == 1 && currentCourses.size() == collect1.size()) {
                continue;
            } else if (currentCourses.size() > 1 && currentCourses.size() == collect1.size()) {
                ArrayList<CourseSchedule> collect2 = currentCourses
                        .stream()
                        .collect(Collectors.collectingAndThen(Collectors.toCollection(()
                                -> new TreeSet<CourseSchedule>(Comparator.comparing(o -> o.getStartClassTime() + "-" + o.getEndClassTime()))), ArrayList::new));
                if (collect2.size() != currentCourses.size()) {
                    throw new BizException("建课失败，当前课程安排与现有课程冲突，请调整相关设置");
                }
            } else {
                for (Date keyDate2 : collect1.keySet()) {
                    List<CourseSchedule> currentCourses1 = collect1.get(keyDate2);
                    if (currentCourses1.size() > ParamEnum.ONE.getCode()) {
                        Map<Integer, List<CourseSchedule>> collect2 = currentCourses1.stream().collect(
                                Collectors.groupingBy(CourseSchedule::getTeacherId));
                        for (Integer teacherID : collect2.keySet()) {
                            if (collect2.get(teacherID).size() > ParamEnum.ONE.getCode()) {
                                throw new BizException(new SimpleDateFormat("yyyy-MM-dd").format(keyDate) + "日的课程安排在教师分配上有冲突!");
                            }
                        }
                        List<Integer> repeatClassGroupIds = currentCourses1.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
                        Integer[] counts = courseScheduleDao.countStudentInClass(repeatClassGroupIds);
                        for (Integer i : counts) {
                            if (i > ParamEnum.ONE.getCode()) {
                                throw new BizException(new SimpleDateFormat("yyyy-MM-dd").format(keyDate) + "日的课程安排有学生重复!");
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/9/29
     * 生成课程名
     */
    @Override
    public void createCourseScheduleName(List<CourseSchedule> courseSchedules) {
        List<Integer> classGroupIds = courseSchedules.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
        HashSet<Integer> temp = new HashSet<>(classGroupIds);
        classGroupIds = new ArrayList<>(temp);
        Map<Integer, String> classIdSubjectNameMap = convertToMap(courseScheduleDao.findClassSubjects(classGroupIds));
        courseSchedules.forEach(courseSchedule -> {
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.MIX)) {
                courseSchedule.setName(courseSchedule.getType().getMsg());
            } else {
                StringBuilder className = new StringBuilder(classIdSubjectNameMap.get(courseSchedule.getClassGroupId()));
                className.append("-");
                className.append(courseSchedule.getType().getMsg());
                courseSchedule.setName(className.toString());
            }
            courseSchedule.setStatus(CourseStatusEnum.NOT_START);
        });
    }

    private Map<Integer, String> convertToMap(String[] result) {
        Map<Integer, String> map = new HashMap<>();
        for (String s : result) {
            map.put(Integer.valueOf(s.split("-")[0]), s.split("-")[1].replace(",", "/"));
        }
        return map;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void vipCourseAdjust(VipGroupCourseAdjustInfoDto vipGroupCourseAdjustInfo) {
        if (Objects.isNull(vipGroupCourseAdjustInfo.getVipGroupId())) {
            throw new BizException("请指定小课");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getCourseCreateStartTime())) {
            throw new BizException("请指定排课起始时间;");
        }
        if (CollectionUtils.isEmpty(vipGroupCourseAdjustInfo.getCourseTimes())) {
            throw new BizException("请指定排课周期");
        }
        if (StringUtils.isBlank(vipGroupCourseAdjustInfo.getCourseScheduleIds())) {
            throw new BizException("请指定需要调整的小课课程");
        }
        Date courseCreateStartTime = vipGroupCourseAdjustInfo.getCourseCreateStartTime();
        Date now = new Date();
        Date today = DateUtil.stringToDate(DateUtil.dateToString(now, DateUtil.ISO_EXPANDED_DATE_FORMAT),
                DateUtil.ISO_EXPANDED_DATE_FORMAT);
        if (courseCreateStartTime.before(today)) {
            throw new BizException("排课起始时间不能小于当前时间");
        }

        boolean needSchoolId = Objects.nonNull(vipGroupCourseAdjustInfo.getTeachMode()) && vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE) && Objects.isNull(vipGroupCourseAdjustInfo.getTeachMode());
        if (needSchoolId) {
            throw new BizException("请设置教学点");
        }

        VipGroup vipGroup = vipGroupDao.get(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
        if (Objects.isNull(vipGroup)) {
            throw new BizException("指定课程不存在");
        }

        int courseNum = courseScheduleDao.countVipGroupCourses(vipGroup.getId().intValue());
        if (courseNum == 0) {
            throw new BizException("未排课的课程不能进行调整");
        }

        ClassGroup classGroup = classGroupDao.findByGroupAndType(vipGroupCourseAdjustInfo.getVipGroupId().toString(), GroupType.VIP.getCode());
        if (Objects.isNull(classGroup)) {
            throw new BizException("对应班级不存在");
        }

        //所有课程编号
        List<Long> courseScheduleIds = Arrays.asList(vipGroupCourseAdjustInfo.getCourseScheduleIds().split(","))
                .stream().map(Long::parseLong).collect(Collectors.toList());
        //所有的课程
        List<CourseSchedule> courseSchedules = courseScheduleDao.findByCourseScheduleIds(courseScheduleIds);

        courseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        if (courseScheduleIds.size() != courseScheduleIds.size()) {
            throw new BizException("部分课程不存在");
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(courseCreateStartTime);
        List<Date> courseStartDates = new ArrayList<>();

        Map<String, Integer> holidayDays = new HashMap<>();
        Map<Integer, Map<String, Integer>> holiday = new HashMap<>();

        try {
            if (vipGroupCourseAdjustInfo.isHoliday()) {
                holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                holidayDays = holiday.get(calendar.get(Calendar.YEAR));
            }
        } catch (DecodeException e) {
            LOGGER.error("节假日解析错误");
            vipGroupCourseAdjustInfo.setHoliday(false);
        }

        while (true) {
            if (vipGroupCourseAdjustInfo.isHoliday() && !holiday.containsKey(calendar.get(Calendar.YEAR))) {
                holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                holidayDays = holiday.get(calendar.get(Calendar.YEAR));
            }
            if (vipGroupCourseAdjustInfo.isHoliday() && holidayDays.containsKey(DateUtil.format(calendar.getTime(), "MMdd"))) {
                calendar.add(Calendar.DATE, 1);
                continue;
            }
            int i = calendar.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = --i;
            }
            for (CourseTimeDto courseTime : vipGroupCourseAdjustInfo.getCourseTimes()) {
                if (Objects.isNull(courseTime.getDayOfWeek())) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() == i) {
                    String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
                    dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
                    Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");
                    Date courseEndTime = DateUtil.addMinutes(courseStartTime, vipGroup.getSingleClassMinutes());
                    courseStartDates.add(DateUtil.stringToDate(dateYmdStr, DateUtil.EXPANDED_DATE_TIME_FORMAT));
                    int settlementNum = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(courseSchedules.get(courseStartDates.size() - 1).getId().intValue());
                    if (settlementNum > 0) {
                        throw new BizException("{}[{}]{}-{}课程已结算",
                                courseSchedules.get(courseStartDates.size() - 1).getName(),
                                courseSchedules.get(courseStartDates.size() - 1).getId(),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getStartClassTime(),
                                        DateUtil.ISO_EXPANDED_DATE_TIME_FORMAT),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getEndClassTime(),
                                        DateUtil.ISO_EXPANDED_DATE_TIME_FORMAT));
                    }
                    int num = studentAttendanceDao.countStudentAttendenceNum(courseSchedules.get(courseStartDates.size() - 1).getId().intValue());
                    if (num > 0) {
                        throw new BizException("{}[{}]{}-{}课程已点名",
                                courseSchedules.get(courseStartDates.size() - 1).getName(),
                                courseSchedules.get(courseStartDates.size() - 1).getId(),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getStartClassTime(),
                                        DateUtil.EXPANDED_DATE_TIME_FORMAT),
                                DateUtil.dateToString(courseSchedules.get(courseStartDates.size() - 1).getEndClassTime(),
                                        DateUtil.EXPANDED_DATE_TIME_FORMAT));
                    }
                    courseSchedules.get(courseStartDates.size() - 1).setStatus(CourseStatusEnum.NOT_START);
                    courseSchedules.get(courseStartDates.size() - 1).setClassDate(courseStartTime);
                    courseSchedules.get(courseStartDates.size() - 1).setStartClassTime(courseStartTime);
                    courseSchedules.get(courseStartDates.size() - 1).setEndClassTime(courseEndTime);
                    if (Objects.nonNull(vipGroupCourseAdjustInfo.getTeachMode())) {
                        if(courseSchedules.get(courseStartDates.size() - 1).getTeachMode().equals(TeachModeEnum.ONLINE)
                            &&vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE)){
                            throw new BizException("暂不支持线上课程转为线下课");
                        }
                        courseSchedules.get(courseStartDates.size() - 1).setTeachMode(vipGroupCourseAdjustInfo.getTeachMode());
                        if (vipGroupCourseAdjustInfo.getTeachMode().equals(TeachModeEnum.OFFLINE)) {
                            if(Objects.nonNull(vipGroupCourseAdjustInfo.getSchoolId())){
                                courseSchedules.get(courseStartDates.size() - 1).setSchoolId(vipGroupCourseAdjustInfo.getSchoolId());
                            }
                        } else {
                            courseSchedules.get(courseStartDates.size() - 1).setSchoolId(null);
                        }
                    }
                }
                if (courseStartDates.size() == courseScheduleIds.size()) {
                    break;
                }
            }
            if (courseStartDates.size() == courseScheduleIds.size()) {
                break;
            }
            calendar.add(Calendar.DATE, 1);
        }
        checkNewCourseSchedules(courseSchedules, false);
        courseScheduleDao.batchUpdate(courseSchedules);
        classGroupService.updateClassGroupInfo(classGroup.getId());
//        vipGroupService.checkVipCourseIsInScore(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
//        courseScheduleStudentPaymentService.updateVipGiveCourse(vipGroup.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void coursePostpone(CoursePostponeDto coursePostPoneInfo) {
        if(StringUtils.isBlank(coursePostPoneInfo.getClassGroupIds())){
            throw new BizException("请指定班级");
        }
        if(Objects.isNull(coursePostPoneInfo.getPauseDate())){
            throw new BizException("请指定课程暂停时间");
        }
        if(Objects.isNull(coursePostPoneInfo.getRecoveryDate())){
            throw new BizException("请指定课程恢复时间");
        }
        //间隔天数
        int betweenDays = DateUtil.daysBetween(coursePostPoneInfo.getPauseDate(), coursePostPoneInfo.getRecoveryDate());
        List<CourseSchedule> classGroupCourseSchedulesWithDate = courseScheduleDao.findClassGroupCourseSchedulesWithDate(coursePostPoneInfo.getClassGroupIds(), coursePostPoneInfo.getPauseDate());

        if(CollectionUtils.isEmpty(classGroupCourseSchedulesWithDate)){
            throw new BizException("选择的班级上在指定日期之后不存在需要调整的课程");
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(coursePostPoneInfo.getRecoveryDate());

        Map<String, Integer> holidayDays = new HashMap<>();
        Map<Integer, Map<String, Integer>> holiday = new HashMap<>();

        classGroupCourseSchedulesWithDate.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

        for (int i=0;i<classGroupCourseSchedulesWithDate.size();i++) {
            CourseSchedule courseSchedule=classGroupCourseSchedulesWithDate.get(i);
            calendar.setTime(courseSchedule.getClassDate());
            calendar.add(Calendar.DATE, betweenDays);
            try {
                if (coursePostPoneInfo.isSkipHoliday() && !holiday.containsKey(calendar.get(Calendar.YEAR))) {
                    holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                    holidayDays = holiday.get(calendar.get(Calendar.YEAR));
                }
            } catch (Exception e) {
                LOGGER.error("节假日解析错误");
                coursePostPoneInfo.setSkipHoliday(false);
            }

            if (coursePostPoneInfo.isSkipHoliday() && holidayDays.containsKey(DateUtil.format(calendar.getTime(), "MMdd"))) {
                betweenDays=betweenDays+7;
                calendar.add(Calendar.DATE, betweenDays);
                i=i-1;
                continue;
            }
            classGroupCourseSchedulesWithDate.get(i).setClassDate(calendar.getTime());
        }
//        checkNewCourseSchedules(classGroupCourseSchedulesWithDate,false);
        courseScheduleDao.batchUpdate(classGroupCourseSchedulesWithDate);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAppendVipGroupCourses(VipGroupCourseAdjustInfoDto vipGroupCourseAdjustInfo) {
        if (Objects.isNull(vipGroupCourseAdjustInfo.getVipGroupId())) {
            throw new BizException("请指定小课");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getCourseCreateStartTime())) {
            throw new BizException("请指定排课起始时间;");
        }
        if (CollectionUtils.isEmpty(vipGroupCourseAdjustInfo.getCourseTimes())) {
            throw new BizException("请指定排课周期");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getSingleClassPrice())) {
            throw new BizException("请指定课程单价");
        }
        if (Objects.isNull(vipGroupCourseAdjustInfo.getCourseCount())) {
            throw new BizException("请指定排课次数");
        }
        Date courseCreateStartTime = vipGroupCourseAdjustInfo.getCourseCreateStartTime();
        Date now = new Date();
        Date today = DateUtil.stringToDate(DateUtil.dateToString(now, DateUtil.ISO_EXPANDED_DATE_FORMAT),
                DateUtil.ISO_EXPANDED_DATE_FORMAT);
        if (courseCreateStartTime.before(today)) {
            throw new BizException("排课起始时间不能小于当前时间");
        }

        VipGroup vipGroup = vipGroupDao.get(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
        if (Objects.isNull(vipGroup)) {
            throw new BizException("指定课程不存在");
        }

        if (vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)) {
            throw new BizException("报名中的课程不能加课");
        }

        ClassGroup classGroup = classGroupDao.findByGroupAndType(vipGroupCourseAdjustInfo.getVipGroupId().toString(), GroupType.VIP.getCode());
        if (Objects.isNull(classGroup)) {
            throw new BizException("对应班级不存在");
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(courseCreateStartTime);

        Map<String, Integer> holidayDays = new HashMap<>();
        Map<Integer, Map<String, Integer>> holiday = new HashMap<>();

        try {
            if (vipGroupCourseAdjustInfo.isHoliday()) {
                holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                holidayDays = holiday.get(calendar.get(Calendar.YEAR));
            }
        } catch (DecodeException e) {
            LOGGER.error("节假日解析错误");
            vipGroupCourseAdjustInfo.setHoliday(false);
        }

        List<CourseSchedule> courseSchedules = new ArrayList<>();

        while (true) {
            if (vipGroupCourseAdjustInfo.isHoliday() && !holiday.containsKey(calendar.get(Calendar.YEAR))) {
                holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                holidayDays = holiday.get(calendar.get(Calendar.YEAR));
            }
            if (vipGroupCourseAdjustInfo.isHoliday() && holidayDays.containsKey(DateUtil.format(calendar.getTime(), "MMdd"))) {
                calendar.add(Calendar.DATE, 1);
                continue;
            }
            int i = calendar.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = --i;
            }
            for (CourseTimeDto courseTime : vipGroupCourseAdjustInfo.getCourseTimes()) {
                if (Objects.isNull(courseTime.getDayOfWeek())) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() == i) {
                    String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
                    dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
                    Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");
                    Date courseEndTime = DateUtil.addMinutes(courseStartTime, vipGroup.getSingleClassMinutes());
                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setGroupType(GroupType.VIP);
                    courseSchedule.setMusicGroupId(vipGroup.getId().toString());
                    courseSchedule.setClassGroupId(classGroup.getId());
                    courseSchedule.setClassDate(courseStartTime);
                    courseSchedule.setStartClassTime(courseStartTime);
                    courseSchedule.setEndClassTime(courseEndTime);
                    courseSchedule.setSchoolId(vipGroup.getTeacherSchoolId());
                    courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                    courseSchedule.setTeachMode(vipGroupCourseAdjustInfo.getTeachMode());
                    courseSchedules.add(courseSchedule);
                }
                if (courseSchedules.size() == vipGroupCourseAdjustInfo.getCourseCount()) {
                    break;
                }
            }
            if (courseSchedules.size() == vipGroupCourseAdjustInfo.getCourseCount()) {
                break;
            }
            calendar.add(Calendar.DATE, 1);
        }
//		checkNewCourseSchedules(courseSchedules,false);
//		courseScheduleDao.batchUpdate(courseSchedules);
        VipGroupApplyDto vipGroupApplyDto = new VipGroupApplyDto();
        VipGroupApplyBaseInfoDto vipGroupApplyBaseInfoDto = new VipGroupApplyBaseInfoDto();
        vipGroupApplyBaseInfoDto.setId(vipGroup.getId());
        vipGroupApplyDto.setVipGroupApplyBaseInfo(vipGroupApplyBaseInfoDto);
        vipGroupApplyDto.setCourseSchedules(courseSchedules);
        vipGroupApplyDto.setSingleClassPrice(vipGroupCourseAdjustInfo.getSingleClassPrice());
        vipGroupService.appendVipGroupCourseSchedules(vipGroupApplyDto);
        classGroupService.updateClassGroupInfo(classGroup.getId());
//        vipGroupService.checkVipCourseIsInScore(vipGroupCourseAdjustInfo.getVipGroupId().longValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void courseAdjust(List<CourseSchedule> newCourseSchedules) {
        Date now = new Date();
        //课程信息处理
        List<Long> courseScheduleIds = newCourseSchedules.stream()
                .map(CourseSchedule::getId)
                .distinct().collect(Collectors.toList());
        List<CourseSchedule> oldCourseScheduleIds = courseScheduleDao.findByCourseScheduleIds(courseScheduleIds);
        Map<Long, List<CourseSchedule>> oldCourseScheduleMap = oldCourseScheduleIds.stream()
                .collect(Collectors.groupingBy(CourseSchedule::getId));
        List<Map<Long, Integer>> courseSettlementMaps = courseScheduleTeacherSalaryDao.checkCoursesIsSettlement(courseScheduleIds);
        Map<Long, Long> courseSettlementMap = MapUtil.convertIntegerMap(courseSettlementMaps);

        newCourseSchedules.forEach(newCourseSchedule -> {
            Long isSettlement = courseSettlementMap.get(newCourseSchedule.getId().longValue());
            if (Objects.nonNull(isSettlement) && isSettlement > 0) {
                throw new BizException("调整的课程中存在已结算的课程");
            }
            List<CourseSchedule> oldCourseSchedules = oldCourseScheduleMap.get(newCourseSchedule.getId());
            oldCourseSchedules.sort(Comparator.comparing(CourseSchedule::getStartClassTime).reversed());
            CourseSchedule oldCourseSchedule = oldCourseSchedules.get(0);
            if (Objects.isNull(newCourseSchedule.getActualTeacherId())) {
                newCourseSchedule.setActualTeacherId(oldCourseSchedule.getActualTeacherId());
            }
            if (Objects.isNull(newCourseSchedule.getSchoolId())) {
                newCourseSchedule.setSchoolId(oldCourseSchedule.getSchoolId());
            }
            int settlementNum = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(oldCourseSchedule.getId().intValue());
            if (settlementNum > 0) {
                throw new BizException("{}[{}]{}-{}课程已结算的",
                        oldCourseSchedule.getName(),
                        oldCourseSchedule.getId(),
                        DateUtil.dateToString(oldCourseSchedule.getStartClassTime(),
                                DateUtil.EXPANDED_DATE_TIME_FORMAT),
                        DateUtil.dateToString(oldCourseSchedule.getEndClassTime(),
                                DateUtil.EXPANDED_DATE_TIME_FORMAT));
            }
            int num = studentAttendanceDao.countStudentAttendenceNum(oldCourseSchedule.getId().intValue());
            if (num > 0) {
                throw new BizException("{}[{}] {}-{}课程已点名",
                        oldCourseSchedule.getName(),
                        oldCourseSchedule.getId(),
                        DateUtil.dateToString(oldCourseSchedule.getStartClassTime(),
                                DateUtil.EXPANDED_DATE_TIME_FORMAT),
                        DateUtil.dateToString(oldCourseSchedule.getEndClassTime(),
                                DateUtil.EXPANDED_DATE_TIME_FORMAT));
            }
            if (oldCourseSchedule.getType().equals(CourseSchedule.CourseScheduleType.VIP)) {
                VipGroup vipGroup = vipGroupDao.get(Long.valueOf(oldCourseSchedule.getMusicGroupId()));
                if(Objects.isNull(vipGroup)){
                    throw new BizException("课程不存在");
                }
                Date endClassTime = DateUtil.addMinutes(newCourseSchedule.getStartClassTime(), vipGroup.getSingleClassMinutes());
                newCourseSchedule.setEndClassTime(endClassTime);
            }
            if(Objects.isNull(newCourseSchedule.getClassGroupId())){
                newCourseSchedule.setClassGroupId(oldCourseSchedule.getClassGroupId());
            }
            if (Objects.isNull(newCourseSchedule.getTeachMode())) {
                newCourseSchedule.setTeachMode(oldCourseSchedule.getTeachMode());
            }
            if(Objects.isNull(newCourseSchedule.getClassDate())){
                newCourseSchedule.setClassDate(oldCourseSchedule.getClassDate());
            }
            if(Objects.isNull(newCourseSchedule.getStartClassTime())){
                newCourseSchedule.setStartClassTime(oldCourseSchedule.getStartClassTime());
            }
            if(Objects.isNull(newCourseSchedule.getEndClassTime())){
                newCourseSchedule.setEndClassTime(oldCourseSchedule.getEndClassTime());
            }
            if (newCourseSchedule.getStartClassTime().after(now)) {
                newCourseSchedule.setStatus(CourseStatusEnum.NOT_START);
            }
            if (newCourseSchedule.getStartClassTime().before(now) && newCourseSchedule.getEndClassTime().after(now)) {
                newCourseSchedule.setStatus(CourseStatusEnum.UNDERWAY);
            }
            if (newCourseSchedule.getEndClassTime().before(now)) {
                newCourseSchedule.setStatus(CourseStatusEnum.OVER);
            }
            if(!CollectionUtils.isEmpty(newCourseSchedule.getTeachingTeacherIdList())){
                if (newCourseSchedule.getTeachingTeacherIdList().contains(newCourseSchedule.getActualTeacherId())){
                    throw new BizException("主教和助教不可重复");
                }
            }
        });
        //课程冲突检测
        checkNewCourseSchedules(newCourseSchedules, false);
        //课程调整
        classStartDateAdjust(newCourseSchedules);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void classStartDateAdjust(List<CourseSchedule> newCourseSchedules) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        List<Long> newCourseScheduleIds = newCourseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toList());
        //获取对应未修改的课程列表
        List<CourseSchedule> oldCourseScheduleList = courseScheduleDao.findByCourseScheduleIds(newCourseScheduleIds);
//		if(oldCourseScheduleList.size()!=newCourseSchedules.size()){
        if (oldCourseScheduleList.size() < newCourseSchedules.size()) {
            throw new BizException("课程信息错误");
        }

        Date now = new Date();
        //明天日期
//        Date tomorrow = DateUtil.addDays1(now, 1);

        //需要生成课程课酬的课程计划
        List<CourseSchedule> needCreateCourseScheduleTeacherSalaryCourse = new ArrayList<>();
        //需要重新学生缴费记录的课
        List<CourseSchedule> needCreateStudentPaymentCourses = new ArrayList<>();

        //课程对应助教集合
        List<CourseScheduleTeacherSalary> teachingTeacherSalarys = courseScheduleDao.findTeachingTeachers(newCourseScheduleIds);
        Map<Long, List<CourseScheduleTeacherSalary>> courseTeachingTeacherMaps = teachingTeacherSalarys.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));

        Map<Long, List<CourseSchedule>> oldCourseScheduleMap = oldCourseScheduleList.stream().collect(Collectors.groupingBy(CourseSchedule::getId));

        Map<Long, CourseSchedule> oldCourseSchedules = new HashMap<>();

        List<Integer> classGroupIds = oldCourseScheduleList.stream().map(CourseSchedule::getClassGroupId).collect(Collectors.toList());
        List<ClassGroup> classGroups = classGroupDao.findByClassGroupIds(classGroupIds);
        Map<Integer, ClassGroup> idClassGroupMap = classGroups.stream().collect(Collectors.toMap(ClassGroup::getId, classGroup -> classGroup));

        SysConfig advanceLeaveHoursConfig = sysConfigService.findByParamName(SysConfigService.ENABLE_TEACHER_COURSE_ADJUST_DEFAULT_HOURS);
        Integer advanceLeaveHours=advanceLeaveHoursConfig.getParanValue(Integer.class);
        List<Map<Long, Integer>> courseLeaveStudentNumMaps = studentAttendanceDao.countCourseLeaveStudentNumWithFourHoursAgo(newCourseScheduleIds, advanceLeaveHours);
        Map<Long,Long> courseLeaveStudentNumMap = MapUtil.convertIntegerMap((courseLeaveStudentNumMaps));

        List<Map<Integer, Integer>> classGroupStudentNumMaps = classGroupStudentMapperDao.countClassGroupsStudentNum(classGroupIds, ClassGroupStudentStatusEnum.NORMAL);
        Map<Integer, Long> classGroupStudentNumMap = MapUtil.convertIntegerMap(classGroupStudentNumMaps);

        newCourseSchedules.forEach(newCourseSchedule -> {

            CourseSchedule oldCourseSchedule = oldCourseScheduleMap.get(newCourseSchedule.getId()).get(0);

            if (!sysUser.getUserType().contains("SYSTEM") && sysUser.getUserType().contains("TEACHER")) {
                Long normalStudentNum = classGroupStudentNumMap.get(oldCourseSchedule.getClassGroupId());
                Long courseLeaveStudentNum = courseLeaveStudentNumMap.get(newCourseSchedule.getId());
                if(oldCourseSchedule.getGroupType().equals(GroupType.VIP)
                        &&Objects.nonNull(courseLeaveStudentNum)
                        &&Objects.nonNull(normalStudentNum)
                        &&courseLeaveStudentNum.intValue()==normalStudentNum.intValue()){
                    if(!DateUtil.isSameDay(now,oldCourseSchedule.getStartClassTime())&&now.after(oldCourseSchedule.getStartClassTime())){
                        throw new BizException("当前时间不可对相关课程进行调整");
                    }
                }else{
                    if(DateUtil.addHours(now,advanceLeaveHours).after(oldCourseSchedule.getStartClassTime())){
                        throw new BizException("请在课程开始前{}小时进行调整",advanceLeaveHours);
                    }
                }
            }

            oldCourseSchedules.put(newCourseSchedule.getId(), oldCourseSchedule);

            if (newCourseSchedule.getStartClassTime().after(now)){
                teacherAttendanceDao.cleanCourseTeacherSignInfo(newCourseSchedule.getId());
                needCreateStudentPaymentCourses.add(oldCourseSchedule);
            }

            boolean courseTimeIsChange = false;
            int newCourseTime = DateUtil.minutesBetween(newCourseSchedule.getStartClassTime(), newCourseSchedule.getEndClassTime());
            int oldCourseTime = DateUtil.minutesBetween(oldCourseSchedule.getStartClassTime(), oldCourseSchedule.getEndClassTime());

            if (newCourseTime != oldCourseTime) {
                courseTimeIsChange = true;
            }

            oldCourseSchedule.setClassDate(newCourseSchedule.getClassDate());
            oldCourseSchedule.setStartClassTime(newCourseSchedule.getStartClassTime());
            oldCourseSchedule.setEndClassTime(newCourseSchedule.getEndClassTime());
            oldCourseSchedule.setStatus(newCourseSchedule.getStatus());

            //被修改的教师编号列表，需要将预计薪水置零
            List<Integer> beReplaceTeacherIds = new ArrayList<>();

            if (oldCourseSchedule.getType() == CourseSchedule.CourseScheduleType.VIP) {
                boolean oldTeacherIsNull = Objects.isNull(oldCourseSchedule.getActualTeacherId());
                boolean newTeacherIsNull = Objects.isNull(newCourseSchedule.getActualTeacherId());
                if (newTeacherIsNull && !oldTeacherIsNull) {
                    newCourseSchedule.setActualTeacherId(oldCourseSchedule.getActualTeacherId());
                    newCourseSchedule.setTeachMode(oldCourseSchedule.getTeachMode());
                }
                boolean oldSchoolIsNull = Objects.isNull(oldCourseSchedule.getSchoolId());
                boolean newSchoolIsNull = Objects.isNull(newCourseSchedule.getSchoolId());
                boolean teacherIsChange = oldTeacherIsNull || (!newTeacherIsNull && !oldCourseSchedule.getActualTeacherId().equals(newCourseSchedule.getActualTeacherId()));
                boolean schoolIsChange = oldSchoolIsNull || (newSchoolIsNull && !oldCourseSchedule.getSchoolId().equals(newCourseSchedule.getSchoolId()));

                boolean needSchoolId = Objects.nonNull(newCourseSchedule.getTeachMode()) && newCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE) && Objects.isNull(newCourseSchedule.getSchoolId());

                if (needSchoolId) {
                    throw new BizException("请设置教学点");
                }

                if (schoolIsChange) {
                    oldCourseSchedule.setSchoolId(newCourseSchedule.getSchoolId());
                }

                if (teacherIsChange) {
                    VipGroup byCourseSchedule = vipGroupDao.findByCourseSchedule(newCourseSchedule.getId().intValue());

                    BigDecimal onlineTeacherSalary = new BigDecimal(0), offlineTeacherSalary = new BigDecimal(0);

                    if (teacherIsChange) {
                        TeacherDefaultVipGroupSalary byTeacherAndCategory = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(newCourseSchedule.getActualTeacherId(), byCourseSchedule.getVipGroupCategoryId());
                        if (Objects.nonNull(byTeacherAndCategory)) {
                            onlineTeacherSalary = byTeacherAndCategory.getOnlineClassesSalary();
                            offlineTeacherSalary = byTeacherAndCategory.getOfflineClassesSalary();
                        }
                    } else {
                        ClassGroupTeacherSalary byClassGroupAndTeacher = classGroupTeacherSalaryDao.findByClassGroupAndTeacher(oldCourseSchedule.getClassGroupId(), newCourseSchedule.getActualTeacherId());
                        if (Objects.nonNull(byClassGroupAndTeacher)) {
                            onlineTeacherSalary = byClassGroupAndTeacher.getOnlineClassesSalary();
                            offlineTeacherSalary = byClassGroupAndTeacher.getSalary();
                        }
                    }

                    List<CourseSchedule> courseSchedules = new ArrayList<>();
                    courseSchedules.add(newCourseSchedule);
                    courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(byCourseSchedule,
                            courseSchedules,
                            onlineTeacherSalary, offlineTeacherSalary);
                    if (Objects.nonNull(oldCourseSchedule.getActualTeacherId()) && teacherIsChange) {
                        beReplaceTeacherIds.add(oldCourseSchedule.getActualTeacherId().intValue());
                    }
                }
            } else {
                if (courseTimeIsChange || (Objects.nonNull(newCourseSchedule.getActualTeacherId())
                        && (Objects.isNull(oldCourseSchedule.getActualTeacherId())
                        || !oldCourseSchedule.getActualTeacherId().equals(newCourseSchedule.getActualTeacherId())))) {
                    if (Objects.nonNull(oldCourseSchedule.getActualTeacherId())) {
                        beReplaceTeacherIds.add(oldCourseSchedule.getActualTeacherId().intValue());
                    }
                } else {
                    //如果主教未修改则不需要调整课酬记录
                    newCourseSchedule.setBishopTeacherSalaryNotCreate(true);
                }
                List<CourseScheduleTeacherSalary> courseTeachingTeacherList = courseTeachingTeacherMaps.get(newCourseSchedule.getId());
                //当前设置的课程助教编号列表
                List<Integer> currentCourseTeachingTeacherIds = new ArrayList<>();
                if (!CollectionUtils.isEmpty(courseTeachingTeacherList)) {
                    currentCourseTeachingTeacherIds = courseTeachingTeacherList.stream().map(CourseScheduleTeacherSalary::getUserId).collect(Collectors.toList());
                }
                //修改后的课程助教编号列表
                List<Integer> newTeachingTeacherIdList = newCourseSchedule.getTeachingTeacherIdList();

                if(Objects.isNull(newTeachingTeacherIdList)){
                    newTeachingTeacherIdList=new ArrayList<>();
                }

                List<Integer> newCreateSalaryTeachingTeacherIds;

                //找出重复的助教编号
                List<Integer> foundInCurrentCourseTeachingTeacherIds = newTeachingTeacherIdList.stream().filter(currentCourseTeachingTeacherIds::contains).collect(Collectors.toList());

                //需要重新生成课酬的助教列表
                newCreateSalaryTeachingTeacherIds = newTeachingTeacherIdList.stream()
                        .filter(userId -> !foundInCurrentCourseTeachingTeacherIds.contains(userId))
                        .collect(Collectors.toList());
                //被替换的助教列表
                List<Integer> beReplaceTeachingTeacherIds = currentCourseTeachingTeacherIds.stream()
                        .filter(userId -> !foundInCurrentCourseTeachingTeacherIds.contains(userId))
                        .collect(Collectors.toList());
                beReplaceTeacherIds.addAll(beReplaceTeachingTeacherIds);

                newCourseSchedule.setTeachingTeacherIdList(newCreateSalaryTeachingTeacherIds);


                if (!newCourseSchedule.isBishopTeacherSalaryNotCreate() || !CollectionUtils.isEmpty(newCreateSalaryTeachingTeacherIds)) {
                    newCourseSchedule.setGroupType(oldCourseSchedule.getGroupType());
                    newCourseSchedule.setMusicGroupId(oldCourseSchedule.getMusicGroupId());
                    //如果主教或者助教发生了变化，则需要重新生成课酬
                    needCreateCourseScheduleTeacherSalaryCourse.add(newCourseSchedule);
                }
            }
            if (Objects.nonNull(newCourseSchedule.getSchoolId())) {
                oldCourseSchedule.setSchoolId(newCourseSchedule.getSchoolId());
            }

            if (Objects.nonNull(newCourseSchedule.getTeachMode())) {
                if (newCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)) {
                    oldCourseSchedule.setSchoolId(null);
                }
                if(oldCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)
                    &&newCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
                    throw new BizException("暂不支持线上课程转为线下课");
                }
                oldCourseSchedule.setTeachMode(newCourseSchedule.getTeachMode());
            }

            oldCourseSchedule.setActualTeacherId(newCourseSchedule.getActualTeacherId());
            courseScheduleDao.update(oldCourseSchedule);
            //删除被修改的教师课酬记录和考勤记录
            if (!CollectionUtils.isEmpty(beReplaceTeacherIds)) {
//				courseScheduleTeacherSalaryDao.batchUpdateTeacherExpectSalary(newCourseSchedule.getId().intValue(),beReplaceTeacherIds);
                courseScheduleTeacherSalaryDao.batchDeleteByCourseAndTeacher(newCourseSchedule.getId(), beReplaceTeacherIds);
                teacherAttendanceDao.batchDeleteByCourseAndUsers(newCourseSchedule.getId().intValue(), beReplaceTeacherIds);
            }
            classGroupService.updateClassGroupInfo(oldCourseSchedule.getClassGroupId());
        });
        //生成修改后的教师课酬
        if (!CollectionUtils.isEmpty(needCreateCourseScheduleTeacherSalaryCourse)) {
            classGroupTeacherMapperService.createCourseScheduleTeacherSalary(needCreateCourseScheduleTeacherSalaryCourse, oldCourseSchedules);
        }
        if(!CollectionUtils.isEmpty(needCreateStudentPaymentCourses)){
            courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentByCourseSchedules(needCreateStudentPaymentCourses);
            studentAttendanceDao.deleteByCourseSchedules(needCreateStudentPaymentCourses.stream().map(CourseSchedule::getId).collect(Collectors.toList()));
        }

        if (!sysUser.getUserType().contains("SYSTEM") && sysUser.getUserType().contains("TEACHER")) {
            if (!CollectionUtils.isEmpty(oldCourseScheduleList) && oldCourseScheduleList.get(0).getGroupType().equals(GroupType.VIP)) {
                vipGroupService.checkVipCourseIsInScore(Long.valueOf(oldCourseScheduleList.get(0).getMusicGroupId()));
            }
        }

//        if(oldCourseScheduleList.get(0).getGroupType().equals(GroupType.VIP)){
//            courseScheduleStudentPaymentService.updateVipGiveCourse(Long.valueOf(oldCourseScheduleList.get(0).getMusicGroupId()));
//        }

        try {
            //推送课时调整
            Set<Integer> teacherIds = newCourseSchedules.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet());
            if (teacherIds == null) {
                teacherIds = new HashSet<>();
            }
            teacherIds.addAll(oldCourseScheduleList.stream().map(e -> e.getActualTeacherId()).collect(Collectors.toSet()));
            Map<Integer, String> map = new HashMap<>(teacherIds.size());
            teacherIds.removeAll(Collections.singleton(null));
            teacherIds.forEach(e -> {
                map.put(e, e.toString());
            });
//		HashMap<Integer,String> map = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(teacherDao.queryPhoneByIds(StringUtils.join(teacherIds, ",")))), HashMap.class);
            if (map != null && map.size() > 0) {
                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT,
                        map, null, 0, "7","TEACHER");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

//		Set<Integer> roleIds = new HashSet<>(1);
//		roleIds.add(SysUserRole.SECTION_MANAGER);
//		classGroupDao.get();
//		sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds),MessageTypeEnum.BACKSTAGE_COURSE_CHANGE,
//				teacher.getRealName());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void courseSwap(Long courseScheduleId1, Long courseScheduleId2) {
        if (courseScheduleId1.equals(courseScheduleId2)) {
            throw new BizException("请选择不同的课程");
        }
        CourseSchedule courseSchedule1 = courseScheduleDao.get(courseScheduleId1);
        CourseSchedule courseSchedule2 = courseScheduleDao.get(courseScheduleId2);

        if (Objects.isNull(courseSchedule1) || Objects.isNull(courseSchedule2)) {
            throw new BizException("未找到对应课程");
        }

        if(!courseSchedule1.getGroupType().equals(courseSchedule2.getGroupType())
            ||!courseSchedule1.getMusicGroupId().equals(courseSchedule2.getMusicGroupId())){
            throw new BizException("不能跨乐团进行课时交换");
        }

        int course1CourseMinutes = DateUtil.minutesBetween(courseSchedule1.getStartClassTime(), courseSchedule1.getEndClassTime());
        int course2CourseMinutes = DateUtil.minutesBetween(courseSchedule2.getStartClassTime(), courseSchedule2.getEndClassTime());

        CourseSchedule temp=new CourseSchedule();
        BeanUtils.copyProperties(courseSchedule1, temp);

        courseSchedule1.setClassDate(courseSchedule2.getClassDate());
        courseSchedule1.setStartClassTime(courseSchedule2.getStartClassTime());
        courseSchedule1.setEndClassTime(DateUtil.addMinutes(courseSchedule1.getStartClassTime(),course1CourseMinutes));

        courseSchedule2.setClassDate(temp.getClassDate());
        courseSchedule2.setStartClassTime(temp.getStartClassTime());
        courseSchedule2.setEndClassTime(DateUtil.addMinutes(courseSchedule2.getStartClassTime(),course2CourseMinutes));

        List<CourseSchedule> courseSchedules = new ArrayList<>();
        courseSchedules.add(courseSchedule1);
        courseSchedules.add(courseSchedule2);
        classStartDateAdjust(courseSchedules);
    }

    @Override
    public void courseSwapWithDay(Date day1, Date day2) {

    }

    @Override
    public List<CourseSchedule> findClassGroupNoStartCourseSchedules(List<Integer> classGroupIds, GroupType groupType) {
        return courseScheduleDao.findClassGroupNoStartCourseSchedules(classGroupIds, groupType);
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/9/24
     * 检测学生是否存在重复
     */
    private void checkStudentIsRepeat(List<Integer> studentIds) {
        Integer[] counts = courseScheduleDao.countStudentInClass(studentIds);
        for (Integer i : counts) {
            if (i > ParamEnum.ONE.getCode()) {
                throw new BizException("所选课程安排日期有学生重复!");
            }
        }
    }

    /**
     * @Author: Joburgess
     * @Date: 2019/9/24
     * 根据课时调整信息增加新课程
     */
    private void createNewCourseByAdjust(List<Date> dates, ClassDateAdjustDto classDateAdjustDto) {
        CourseSchedule schedule = courseScheduleDao.get(classDateAdjustDto.getId());
        List<CourseSchedule> courseSchedules = new ArrayList<>();
        courseScheduleDao.delete(classDateAdjustDto.getId());
        for (Date date : dates) {
            CourseSchedule courseSchedule = new CourseSchedule();
            BeanUtils.copyProperties(schedule, courseSchedule);
            courseSchedule.setClassDate(date);
            courseSchedule.setStartClassTime(classDateAdjustDto.getStartClassTime());
            courseSchedule.setEndClassTime(classDateAdjustDto.getEndClassTime());
            courseSchedule.setTeacherId(classDateAdjustDto.getTeacherId());
            courseSchedules.add(courseSchedule);
        }
        courseScheduleDao.batchAddCourseSchedules(courseSchedules);
    }

    @Override
    public Object findStudentCourseScheduleRecords(StudentCourseScheduleRecordQueryInfo queryInfo) {
        SysUser user = sysUserFeignService.queryUserInfo();
        queryInfo.setUserId(user.getId().longValue());
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (queryInfo.getIsAttend() == YesOrNoEnum.YES) {
            List<StudentCourseScheduleRecordDto> notStartRecords = courseScheduleDao.findStudentCourseScheduleNotStartRecords(user.getId().longValue(),
                    queryInfo.getDate());
            if (notStartRecords != null && notStartRecords.size() > 0) {
//				Set<Integer> classGroupIds = notStartRecords.stream().map(e -> e.getClassGroupId()).collect(Collectors.toSet());
//				Map<Integer,Integer> totalNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalNumByClassGroupId(classGroupIds,queryInfo.getDate()));
//				Map<Integer,Integer> currentNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countCurrentNumByClassGroupId(classGroupIds,queryInfo.getDate()));
                notStartRecords.forEach(e -> {
                    e.setRestOfClass(notStartRecords.size());
                });
            }
            pageInfo.setRows(notStartRecords);
            return pageInfo;
        }

        Map<String, Object> params = new HashMap<String, Object>();
        if (queryInfo.getType() != null && queryInfo.getType().equals("MUSICGROUP")) {
            queryInfo.setType("MUSIC");
        }
        MapUtil.populateMap(params, queryInfo);

        List dataList = null;
        int count = courseScheduleDao.countStudentCourseScheduleRecords(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = courseScheduleDao.findStudentCourseScheduleRecords(params);
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void courseScheduleCommplaint(CourseScheduleComplaints courseScheduleComplaints) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (Objects.isNull(user)) {
            throw new BizException("请登录");
        }

        if (Objects.isNull(courseScheduleComplaints.getCourseScheduleId())) {
            throw new BizException("请指定需要评价的课程");
        }

        if (StringUtils.isBlank(courseScheduleComplaints.getReason())) {
            throw new BizException("请说明写下您的评价");
        }

        if (StringUtils.length(courseScheduleComplaints.getReason()) > 150) {
            throw new BizException("字符长度超限");
        }

        int settlementTimes = courseScheduleTeacherSalaryDao.checkCourseIsSettlement(courseScheduleComplaints.getCourseScheduleId().intValue());
        if (settlementTimes > 0) {
            throw new BizException("该课程已结算");
        }

        courseScheduleComplaints.setUserId(user.getId());

        CourseScheduleComplaints byUserAndCourse = courseScheduleComplaintsDao.findByUserAndCourse(courseScheduleComplaints.getUserId().longValue(), courseScheduleComplaints.getCourseScheduleId());
        if (byUserAndCourse != null) {
            throw new BizException("您已经对该课程做出了评价!");
        }

        CourseScheduleDto courseSchedules = courseScheduleDao.getCourseSchedules(courseScheduleComplaints.getCourseScheduleId());
        Date now = new Date();
        if (!courseSchedules.getStatus().equals(CourseStatusEnum.OVER)) {
            throw new BizException("该课程还未结束");
        }
        int i = DateUtil.daysBetween(courseSchedules.getEndClassTime(), now);
        if (i > Integer.parseInt(sysConfigDao.findConfigValue(SysConfigService.VIP_APPEAL_DAYS_RANGE))) {
            throw new BizException("该课程已超过可申诉时间范围!");
        }
        courseScheduleComplaints.setUserId(user.getId());
        courseScheduleComplaints.setStatus(AuditStatusEnum.ING);
        if (courseScheduleComplaints.getScore() > 2) {
            courseScheduleComplaints.setStatus(AuditStatusEnum.PASS);
        }
        courseScheduleComplaintsDao.insert(courseScheduleComplaints);
        if (courseScheduleComplaints.getScore() > 2) {
            return;
        }
        //学员提起申诉通知
        CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleComplaints.getCourseScheduleId());
        Set<Integer> roleIds = new HashSet<>(1);
        roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
        Map<String, Long> memo = new HashMap<>(1);
        memo.put("courseScheduleComplaintsId", courseScheduleComplaints.getId());
        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, user.getOrganId()), MessageTypeEnum.BACKSTAGE_STUDENT_APPEAL, JSONObject.toJSONString(memo), courseSchedule.getName(), user.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void courseScheduleCommplaintAudit(Long id, Double teacherLiabilityRatio, Double studentLiabilityRatio, AuditStatusEnum status) {

        if (status == AuditStatusEnum.ING) {
            throw new BizException("审批状态不正确");
        }

        CourseScheduleComplaints courseScheduleComplaints = courseScheduleComplaintsDao.get(id);
        if (Objects.isNull(courseScheduleComplaints)) {
            throw new BizException("投诉记录不存在");
        }
        courseScheduleComplaints.setTeacherLiabilityRatio(teacherLiabilityRatio);
        courseScheduleComplaints.setStudentLiabilityRatio(studentLiabilityRatio);
        courseScheduleComplaints.setStatus(status);
        courseScheduleComplaintsDao.update(courseScheduleComplaints);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCourseScheduleToOverStatus() {

        Date date = new Date();
        //课程已结束，更新“未签到”学生的状态未“旷课”
		/*List<StudentAttendance> studentAttendanceList = courseScheduleDao.queryUnsignedStudentList();
		if (studentAttendanceList != null && studentAttendanceList.size() > 0) {
			// 获取老师的考勤记录
			Map<Long, TeacherAttendance> teacherAttendanceMap = teacherAttendanceDao
					.findTeacherIdByCourseSchedule(studentAttendanceList.stream().map(sa -> sa.getCourseScheduleId()).collect(Collectors.toList())).stream()
					.collect(Collectors.toMap(TeacherAttendance::getCourseScheduleId, ta -> ta));
			
			Date updateTime = DateUtil.stringToDate("19700101 000000", DateUtil.DATE_TIME_FORMAT);
			for (Iterator<StudentAttendance> list = studentAttendanceList.iterator(); list.hasNext();) {
				StudentAttendance studentAttendance = list.next();
				TeacherAttendance teacherAttendance = teacherAttendanceMap.get(studentAttendance.getCourseScheduleId());
				if (teacherAttendance != null && teacherAttendance.getSignOutTime() == null) {
					list.remove();
				} else {
					studentAttendance.setStatus(StudentAttendanceStatusEnum.TRUANT);
					studentAttendance.setRemark("课程已结束，自动补旷课");
					if (Objects.isNull(studentAttendance.getCurrentClassTimes())) {
						studentAttendance.setCurrentClassTimes(1);
					} else {
						studentAttendance.setCurrentClassTimes(studentAttendance.getCurrentClassTimes() + 1);
					}
					studentAttendance.setCreateTime(date);
					studentAttendance.setUpdateTime(updateTime);
				}
			}

			if (studentAttendanceList != null && studentAttendanceList.size() > 0) {
				studentAttendanceDao.addStudentAttendances(studentAttendanceList);
			}
		}*/

        //自动更新课程状态至“已结束”
        List<CourseSchedule> list = courseScheduleDao.queryFinishedWithNoUpdateStatus();

        List<CourseSchedule> updateList = new ArrayList<CourseSchedule>();
        List<Integer> classGroupIds = new ArrayList<Integer>();
        List<Long> courseScheduleIdList = new ArrayList<Long>();

        for (CourseSchedule courseSchedule : list) {
            courseSchedule.setStatus(CourseStatusEnum.OVER);
            courseSchedule.setUpdateTime(date);
            updateList.add(courseSchedule);

            if (!classGroupIds.contains(courseSchedule.getClassGroupId())) {
                classGroupIds.add(courseSchedule.getClassGroupId());
            }

            if (courseSchedule.getGroupType() == GroupType.VIP) {
                courseScheduleIdList.add(courseSchedule.getId());
            }
        }

        if (updateList.size() > 0) {
            courseScheduleDao.batchUpdate(updateList);
        }

        // 更新班级已上课次
        if (classGroupIds.size() > 0) {
            classGroupService.batchIncreaseClassTimes(classGroupIds);

            //查询班级信息
//            List<ClassGroup> classGroupList = classGroupService.findClassGroupByIds(classGroupIds.stream().map(e -> e.toString()).collect(Collectors.joining(",")));
//
//            List<String> vipGroupIdList = new ArrayList<String>();
//            for (ClassGroup classGroup : classGroupList) {
//                if (classGroup.getGroupType() == GroupType.VIP && classGroup.getCurrentClassTimes() == classGroup.getTotalClassTimes().intValue()) {
//                    if (!vipGroupIdList.contains(classGroup.getMusicGroupId())) {
//                        vipGroupIdList.add(classGroup.getMusicGroupId());
//                    }
//                }
//            }
//            if (vipGroupIdList.size() > 0) {
//                List<VipGroup> vipGroupList = vipGroupDao.queryByIds(vipGroupIdList.stream().collect(Collectors.joining(",")));
//                for (VipGroup vipGroup : vipGroupList) {
//                    if (!vipGroup.getStatus().equals(VipGroupStatusEnum.PAUSE)
//                            && !vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)) {
//                        vipGroup.setStatus(VipGroupStatusEnum.FINISHED);
//                    }
//                    vipGroup.setUpdateTime(date);
//                }
//                vipGroupDao.batchUpdate(vipGroupList);
//            }
        }

        /*if (courseScheduleIdList.size() > 0) {
            // vip课自动签退
            teacherAttendanceDao.updateViPSignOutStatus(courseScheduleIdList.stream().map(a -> a.toString()).collect(Collectors.joining(",")));
        }*/

        return true;
    }

    @Override
    public PageInfo queryTeacherClassCourseSchedule(CourseScheduleQueryInfo queryInfo) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (null == user) {
            throw new BizException("请登录");
        }
        queryInfo.setUserId(user.getId().longValue());
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (Objects.isNull(queryInfo.getDate())) {
            queryInfo.setDate(new Date());
        }

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

        List<TeacherClassCourseSchudeleDto> dataList = null;
        int count = 0;
        if (Objects.isNull(queryInfo.getOnlyHistory()) || queryInfo.getOnlyHistory() == 0) {
            count = courseScheduleDao.countTeacherClassCourseSchedule(params);
        } else {
            count = courseScheduleDao.countTeacherHistoryClassCourseSchedule(params);
        }
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            if (Objects.isNull(queryInfo.getOnlyHistory()) || queryInfo.getOnlyHistory() == 0) {
                dataList = courseScheduleDao.queryTeacherClassCourseSchedule(params);
            } else {
                dataList = courseScheduleDao.queryTeacherHistoryClassCourseSchedule(params);
            }
            List<Integer> courseIds = dataList.stream().map(teacherClassCourseSchudeleDto -> teacherClassCourseSchudeleDto.getCourseScheduleId().intValue()).collect(Collectors.toList());
            List<Map<Integer, Integer>> currentClassTimesByCourses = studentAttendanceDao.getCurrentClassTimesByCourses(courseIds);
            if (!CollectionUtils.isEmpty(currentClassTimesByCourses)) {
                Map<Integer, Integer> currentClassTimesWithCourse = MapUtil.convertIntegerMap(currentClassTimesByCourses);
                dataList.forEach(e -> {
                    e.setCurrentClassTimes(currentClassTimesWithCourse.get(e.getCourseScheduleId()));
                });
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public CourseAttendanceDetailHeadInfoDto findCourseAttendanceDetailHeadInfo(Long courseScheduleId) {
        if (Objects.isNull(courseScheduleId)) {
            throw new BizException("请指定课程");
        }
        CourseAttendanceDetailHeadInfoDto courseAttendanceDetailHeadInfoDto = courseScheduleDao.findByCourse(courseScheduleId);
        courseAttendanceDetailHeadInfoDto.setLatestAttendanceTime(studentAttendanceDao.findLatestAttendanceDate(courseScheduleId));
        return courseAttendanceDetailHeadInfoDto;
    }

    @Override
    public void checkMusicGroupClassCourse(String musicGroupId) {
        if (Objects.isNull(musicGroupId)) {
            throw new BizException("请指定乐团");
        }
        List<Map<Integer, Long>> maps = courseScheduleDao.countClassCourseNumByMusicGroup(musicGroupId);
        Map<Integer, Long> classCourseNumMap = MapUtil.convertIntegerMap(maps);
        List<Integer> collect = classCourseNumMap
                .entrySet()
                .stream()
                .filter(integerLongEntry -> integerLongEntry.getValue() <= 0)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(collect)) {
            List<String> classGroupNamesByClassGroups = classGroupDao.findClassGroupNamesByClassGroups(collect);
            String classNamesStr = StringUtils.join(classGroupNamesByClassGroups, ",");
            throw new BizException(classNamesStr + "班级未排课");
        }
    }

    @Override
    public Map<Integer, Integer> findCourseScheduleCurrentTimes(List<Integer> courseSchedules) {
        List<Map<Integer, Integer>> courseScheduleCurrentTimes = courseScheduleDao.findCourseScheduleCurrentTimes(courseSchedules);
        return MapUtil.convertIntegerMap(courseScheduleCurrentTimes);
    }

    @Override
    public List<CourseSchedule> findNoStartCoursesByClassGroupId(Integer classGroupId) {
        return courseScheduleDao.findNoStartCoursesByClassGroupId(classGroupId);
    }


    @Override
    public void studentCoursesScheduleRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryStudentCoursesTimesOfTomorrow();
        for (Mapper mapper : mapperList) {
            Integer userId = Integer.parseInt(mapper.getKey().toString());
            Integer size = Integer.parseInt(mapper.getValue().toString());

            Map<Integer, String> receivers = new HashMap<Integer, String>();
            receivers.put(userId, userId + "");

            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_HAVE_COURSE_MESSAGE, receivers, null, 0, "2","STUDENT", size);
        }
    }

    @Override
    public void studentSignInRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryStudentNotStartCourseScheduleIn90Mins();
        if (mapperList != null && mapperList.size() > 0) {
            for (Mapper mapper : mapperList) {
                Map<Integer, String> receivers = new HashMap<Integer, String>();
                receivers.put((Integer) mapper.getKey(), mapper.getKey() + "");

                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_ATTEND_COURSE_MESSAGE, receivers, null, 0, "2","STUDENT", mapper.getValue());
            }
        }
    }

    @Override
    public void teacherCoursesScheduleRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryTeacherCoursesTimesOfTomorrow();
        for (Mapper mapper : mapperList) {
            Integer userId = (Integer) mapper.getKey();
            String teacherName = (String) mapper.getValue();

            Map<Integer, String> receivers = new HashMap<Integer, String>();
            receivers.put(userId, userId + "");

            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_HAVE_COURSE_MESSAGE,
                    receivers, null, 0, "2","TEACHER", teacherName);
        }
    }

    @Override
    public void teacherSignInRemind() {
        List<Mapper> mapperList = courseScheduleDao.queryTeacherNotStartCourseScheduleIn30Mins();
        for (Mapper mapper : mapperList) {
            Integer userId = (Integer) mapper.getKey();
            String scheduleName = (String) mapper.getValue();

            Map<Integer, String> receivers = new HashMap<Integer, String>();
            receivers.put(userId, userId + "");

            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_ATTEND_CLASS_MESSAGE,
                    receivers, null, 0, "2","TEACHER", scheduleName);
        }
    }

    @Override
    public List<CourseSchedule> findCourseScheduleByClassGroup(Integer classGroupId) {
        if (Objects.isNull(classGroupId)) {
            throw new BizException("请指定班级");
        }
        ClassGroup classGroup = classGroupDao.get(classGroupId);
        if (Objects.isNull(classGroup)) {
            throw new BizException("指定的班级不存在");
        }
        List<Integer> classGroupIds = new ArrayList<>();
        classGroupIds.add(classGroupId);
        if (classGroup.getType().equals(ClassGroupTypeEnum.MIX)) {
            List<ClassGroup> mixClassChildClassGroup = classGroupDao.findMixClassChildClassGroup(classGroupId);
            List<Integer> childClassGroupIds = mixClassChildClassGroup.stream()
                    .map(ClassGroup::getId)
                    .collect(Collectors.toList());
            classGroupIds.addAll(childClassGroupIds);
        }
        return courseScheduleDao.findByClassGroups(classGroupIds);
    }

    @Override
    public Object findVipGroupCourseSchedules(VipGroupQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());

        if (Objects.isNull(queryInfo.getVipGroupId())) {
            throw new BizException("请指定vip课程");
        }

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

        VipGroup vipGroup = vipGroupDao.get(queryInfo.getVipGroupId());
        if (Objects.isNull(vipGroup)) {
            throw new BizException("指定的vip课不存在");
        }

        List<CourseSchedule> dataList;
        if (vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)) {
            dataList = JSON.parseArray(vipGroup.getCourseSchedulesJson(), CourseSchedule.class);
        } else {
            dataList = courseScheduleDao.findGroupCourseSchedules(vipGroup.getId(),GroupType.VIP.getCode());
        }

        int count = dataList.size();
        if (count > 0) {
            pageInfo.setTotal(count);
            if (vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)) {
                dataList = dataList.stream().skip(pageInfo.getOffset()).limit(pageInfo.getLimit()).collect(Collectors.toList());
                dataList.forEach(courseSchedule -> {
                    courseSchedule.setIsSettlement(0);
                });
            } else {
                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);
                dataList.forEach(courseSchedule -> {
                    Long isSettlement = courseSettlementMap.get(courseSchedule.getId().longValue());
                    if (Objects.isNull(isSettlement) || isSettlement <= 0) {
                        courseSchedule.setIsSettlement(0);
                    } else {
                        courseSchedule.setIsSettlement(1);
                    }
                });
            }
        }
        pageInfo.setRows(dataList);
        Map<String, Object> result = new HashMap<>();
        result.put("pageInfo", pageInfo);
        result.put("singleClassMinutes", vipGroup.getSingleClassMinutes());
        return result;
    }

    @Override
    public List<CourseSchedule> createCourses(CourseGenerateDto courseGenerateInfo) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(courseGenerateInfo.getCourseCreateStartTime());

        Map<String, Integer> holidayDays = new HashMap<>();
        Map<Integer, Map<String, Integer>> holiday = new HashMap<>();

        try {
            if (courseGenerateInfo.isSkipHoliday()) {
                holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                holidayDays = holiday.get(calendar.get(Calendar.YEAR));
            }
        } catch (DecodeException e) {
            LOGGER.error("节假日解析错误");
            courseGenerateInfo.setSkipHoliday(false);
        }

        List<CourseSchedule> courseSchedules = new ArrayList<>();

        while (true) {
            if (courseGenerateInfo.isSkipHoliday() && !holiday.containsKey(calendar.get(Calendar.YEAR))) {
                holiday = jiaRiFeignService.query(calendar.get(Calendar.YEAR));
                holidayDays = holiday.get(calendar.get(Calendar.YEAR));
            }
            if (courseGenerateInfo.isSkipHoliday() && holidayDays.containsKey(DateUtil.format(calendar.getTime(), "MMdd"))) {
                calendar.add(Calendar.DATE, 1);
                continue;
            }
            int i = calendar.get(Calendar.DAY_OF_WEEK);
            if (i == 1) {
                i = 7;
            } else {
                i = --i;
            }
            for (CourseTimeDto courseTime : courseGenerateInfo.getCourseTimes()) {
                if (Objects.isNull(courseTime.getDayOfWeek())) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() < 1 || courseTime.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误");
                }
                if (courseTime.getDayOfWeek() == i) {
                    String dateYmdStr = DateUtil.dateToString(calendar.getTime(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
                    dateYmdStr = dateYmdStr + " " + courseTime.getStartClassTime();
                    Date courseStartTime = DateUtil.stringToDate(dateYmdStr, "yyyy-MM-dd HH:mm");
                    Date courseEndTime = DateUtil.addMinutes(courseStartTime, courseGenerateInfo.getSingleClassMinutes());
                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setClassDate(courseStartTime);
                    courseSchedule.setStartClassTime(courseStartTime);
                    courseSchedule.setEndClassTime(courseEndTime);
                    courseSchedules.add(courseSchedule);
                }
                if (courseSchedules.size() == courseGenerateInfo.getCourseCount()) {
                    break;
                }
            }
            if (courseSchedules.size() == courseGenerateInfo.getCourseCount()) {
                break;
            }
            calendar.add(Calendar.DATE, 1);
        }
        return courseSchedules;
    }

    @Override
    public PageInfo<CourseScheduleEndDto> endFindCourseSchedules(EndCourseScheduleQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>(16);
        MapUtil.populateMap(params, queryInfo);
        if(StringUtils.isNotBlank(queryInfo.getTeacherName())){
            List<TeacherBasicDto> teachers = teacherDao.searchTeachers(params);
            if(!CollectionUtils.isEmpty(teachers)){
                List<Integer> teacherIds = teachers.stream().map(TeacherBasicDto::getId).collect(Collectors.toList());
                params.put("teacherIdList",StringUtils.join(teacherIds.toArray(),","));
            }
        }
        Set<Integer> courseScheduleIdSet = new HashSet<>();
        courseScheduleIdSet.addAll(courseScheduleDao.queryMusicCourseScheduleIds(params));
        courseScheduleIdSet.addAll(courseScheduleDao.queryVipCourseScheduleIds(params));
        courseScheduleIdSet.addAll(courseScheduleDao.queryPracticeCourseScheduleIds(params));
        if(courseScheduleIdSet.size() == 0){
            return pageInfo;
        }
        params.put("courseScheduleIds", courseScheduleIdSet);
        List<CourseScheduleEndDto> results = new ArrayList<>();
        int count = courseScheduleDao.endCountCourseSchedules(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            results = courseScheduleDao.endFindCourseSchedules(params);
            List<Long> courseScheduleIds = results.stream().map(CourseScheduleEndDto::getId).collect(Collectors.toList());
            List<TeacherAttendance> teacherAttendances = teacherAttendanceDao.findTeacherIdByCourseSchedule(courseScheduleIds);
            Map<Long, List<TeacherAttendance>> courseTeacherAttendanceMap = teacherAttendances.stream().collect(Collectors.groupingBy(TeacherAttendance::getCourseScheduleId));
            List<Map<Integer, Integer>> studentNumCourseMaps = studentAttendanceDao.countStudentAttendancesByCourses(courseScheduleIds);
            Map<Integer, Long> studentNumCourseMap = MapUtil.convertIntegerMap(studentNumCourseMaps);
            List<Group> groups=new ArrayList<>();
            groups.add(null);
            List<Integer> teacherIds=new ArrayList<>();
            for (CourseScheduleEndDto courseScheduleEndDto : results) {
                Group group=new Group(courseScheduleEndDto.getMusicGroupId(),courseScheduleEndDto.getGroupType());
                groups.add(group);
                teacherIds.add(courseScheduleEndDto.getActualTeacherId());
            }
            List<Map<Integer, String>> nameIdMaps = teacherDao.queryNameByIds(StringUtils.join(teacherIds,","));
            Map<Integer, String> nameIdMap=MapUtil.convertIntegerMap(nameIdMaps);
            groups = groupDao.findByGroupIds(groups);
            Map<String, Map<GroupType, List<Group>>> groupsGroupByGroup = groups.stream().collect(Collectors.groupingBy(Group::getId, Collectors.groupingBy(Group::getGroupType)));
            //获取班级声部名称
            List<Map<Integer, String>> classGroupSubjectNameMaps = classGroupDao.findClassGroupSubjectNameMaps(courseScheduleIds);
            Map<Integer, String> classGroupSubjectNameMap = MapUtil.convertIntegerMap(classGroupSubjectNameMaps);
            results.forEach(result -> {
                Map<GroupType, List<Group>> groupsTypeMap = groupsGroupByGroup.get(result.getMusicGroupId());
                result.setTeacher(null);
                if(Objects.nonNull(groupsTypeMap)){
                    List<Group> groupTemps = groupsTypeMap.get(result.getGroupType());
                    if(!CollectionUtils.isEmpty(groupTemps)){
                        result.setGroupName(groupTemps.get(0).getGroupName());
                        result.setOrganName(groupTemps.get(0).getOrganName());
                    }
                }
                result.setTeacherName(nameIdMap.get(result.getActualTeacherId()));
                result.setSubjectName(classGroupSubjectNameMap.get(result.getId()));
                List<TeacherAttendance> courseTeacherAttendances = courseTeacherAttendanceMap.get(result.getId());
                if(!CollectionUtils.isEmpty(courseTeacherAttendances)){
                    TeacherAttendance teacherAttendance=courseTeacherAttendances.get(0);
                    result.setIsSignIn(Objects.isNull(teacherAttendance.getSignInStatus())?3:teacherAttendance.getSignInStatus().getCode());
                    result.setIsSignOut(Objects.isNull(teacherAttendance.getSignOutStatus())?3:teacherAttendance.getSignOutStatus().getCode());
                    result.setSignInTime(teacherAttendance.getSignInTime());
                    result.setSignOutTime(teacherAttendance.getSignOutTime());
                    result.setRemark(teacherAttendance.getRemark());
                }
                Long studentNum = studentNumCourseMap.get(result.getId());
                if (Objects.nonNull(studentNum)) {
                    result.setIsCallNames(studentNum > 0 ? YesOrNoEnum.YES : YesOrNoEnum.NO);
                } else {
                    result.setIsCallNames(YesOrNoEnum.NO);
                }
            });
        }
        pageInfo.setRows(results);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void practiceCourseAdjust(CourseSchedule courseSchedule) {
        if(Objects.isNull(courseSchedule.getId())){
            throw new BizException("请指定课程");
        }
        if(Objects.isNull(courseSchedule.getStartClassTime())){
            throw new BizException("请指定上课时间");
        }
        CourseSchedule oldCourseSchedule = courseScheduleDao.get(courseSchedule.getId());
        if(Objects.isNull(oldCourseSchedule)){
            throw new BizException("未找到对应课程");
        }
        if(!oldCourseSchedule.getGroupType().equals(GroupType.PRACTICE)){
            throw new BizException("请选择陪练课");
        }
        Integer practiceCourseMinutes=25;
        SysConfig practiceCourseMinutesConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_COURSE_MINUTES);
        if(Objects.nonNull(practiceCourseMinutesConfig)){
            practiceCourseMinutes=practiceCourseMinutesConfig.getParanValue(Integer.class);
        }
        oldCourseSchedule.setClassDate(courseSchedule.getStartClassTime());
        oldCourseSchedule.setStartClassTime(courseSchedule.getStartClassTime());
        oldCourseSchedule.setEndClassTime(DateUtil.addMinutes(courseSchedule.getStartClassTime(),practiceCourseMinutes));
        List<CourseSchedule> courseSchedules=new ArrayList<>();
        courseSchedules.add(oldCourseSchedule);
        checkNewCourseSchedules(courseSchedules,false);
        courseScheduleDao.update(oldCourseSchedule);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void practiceCourseTeacherAdjust(Long courseScheduleId,Integer teacherId) {
        if(Objects.isNull(courseScheduleId)){
            throw new BizException("请指定课程");
        }
        if(Objects.isNull(teacherId)){
            throw new BizException("请指定上课老师");
        }
        CourseSchedule oldCourseSchedule = courseScheduleDao.get(courseScheduleId);
        if(Objects.isNull(oldCourseSchedule)){
            throw new BizException("未找到对应课程");
        }
        if(!oldCourseSchedule.getGroupType().equals(GroupType.PRACTICE)){
            throw new BizException("请选择陪练课");
        }
        if(teacherId.equals(oldCourseSchedule.getActualTeacherId())){
            throw new BizException("请选择不同的老师");
        }
        oldCourseSchedule.setActualTeacherId(teacherId);
        List<CourseSchedule> courseSchedules = new ArrayList<>();
        courseSchedules.add(oldCourseSchedule);
        checkNewCourseSchedules(courseSchedules,false);
        courseScheduleDao.update(oldCourseSchedule);
        Set<Long> courseScheduleIds = courseSchedules.stream().map(e -> e.getId()).collect(Collectors.toSet());
        courseScheduleTeacherSalaryDao.batchUpdateTeacher(courseScheduleIds,teacherId);
        Map<Integer, String> map = new HashMap<>(2);
        map.put(teacherId,teacherId.toString());
        map.put(oldCourseSchedule.getActualTeacherId(),oldCourseSchedule.getActualTeacherId().toString());
        if (map != null && map.size() > 0) {
            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT,
                    map, null, 0, "7","TEACHER");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void practiceGroupTeacherAdjust(String practiceGroupId, Integer teacherId) {
        if(StringUtils.isEmpty(practiceGroupId)){
            throw new BizException("请指定课程组");
        }
        if(Objects.isNull(teacherId)){
            throw new BizException("请指定上课老师");
        }
        List<CourseSchedule> courseSchedules = courseScheduleDao.findSurplusCourseWithGroup(GroupType.PRACTICE,practiceGroupId);
        if(courseSchedules != null && courseSchedules.size() > 0){
            courseSchedules = courseSchedules.stream().filter(courseSchedule -> !courseSchedule.getActualTeacherId().equals(teacherId)).collect(Collectors.toList());
        }
        if(courseSchedules == null || courseSchedules.size() == 0){
            throw new BizException("没有可调整课程");
        }
        Integer oldTeacherId = courseSchedules.stream().map(e -> e.getActualTeacherId()).findFirst().get();
        if(teacherId.equals(oldTeacherId)){
            throw new BizException("请选择不同的老师");
        }
        courseSchedules.forEach(e->{
            e.setActualTeacherId(teacherId);
        });
        checkNewCourseSchedules(courseSchedules,false);
        Set<Long> courseScheduleIds = courseSchedules.stream().map(e -> e.getId()).collect(Collectors.toSet());
        courseScheduleDao.batchUpdate(courseSchedules);
        courseScheduleTeacherSalaryDao.batchUpdateTeacher(courseScheduleIds,teacherId);
        Map<Integer, String> map = new HashMap<>(2);
        map.put(teacherId,teacherId.toString());
        map.put(oldTeacherId,oldTeacherId.toString());
        if (map != null && map.size() > 0) {
            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_COURSE_SCHEDULE_CHANGE_RESULT,
                    map, null, 0, "7","TEACHER");
        }
    }
}
