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

import static com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PaymentCalenderStatusEnum.AUDITING;
import static com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PaymentCalenderStatusEnum.NO;
import static com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PaymentType.SPAN_GROUP_CLASS_ADJUST;
import static com.ym.mec.biz.dal.enums.GroupType.COMM;
import static com.ym.mec.biz.dal.enums.GroupType.MUSIC;
import static com.ym.mec.biz.dal.enums.GroupType.PRACTICE;
import static com.ym.mec.biz.dal.enums.GroupType.VIP;
import static com.ym.mec.biz.dal.enums.MusicGroupStatusEnum.PROGRESS;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

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.service.*;
import com.ym.mec.common.entity.HttpResponseResult;
import com.ym.mec.util.collection.ListUtil;

import org.apache.commons.lang3.StringUtils;
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 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.biz.dal.entity.CourseSchedule.CourseScheduleType;
import com.ym.mec.biz.dal.enums.ClassGroupStudentStatusEnum;
import com.ym.mec.biz.dal.enums.ClassGroupTypeEnum;
import com.ym.mec.biz.dal.enums.CourseStatusEnum;
import com.ym.mec.biz.dal.enums.GroupType;
import com.ym.mec.biz.dal.enums.MusicGroupStatusEnum;
import com.ym.mec.biz.dal.enums.SalarySettlementTypeEnum;
import com.ym.mec.biz.dal.enums.StudentAttendanceStatusEnum;
import com.ym.mec.biz.dal.enums.TeachModeEnum;
import com.ym.mec.biz.dal.enums.TeachTypeEnum;
import com.ym.mec.biz.dal.enums.VipGroupStatusEnum;
import com.ym.mec.biz.dal.enums.YesOrNoEnum;
import com.ym.mec.biz.dal.page.ClassGroupQueryInfo;
import com.ym.mec.biz.dal.page.CourseScheduleQueryInfo;
import com.ym.mec.biz.dal.page.EndCourseScheduleQueryInfo;
import com.ym.mec.biz.dal.page.StudentPayLogQueryInfo;
import com.ym.mec.biz.dal.page.TeacherMusicClassQueryInfo;
import com.ym.mec.biz.dal.page.VipClassQueryInfo;
import com.ym.mec.biz.dal.page.queryMusicGroupCourseScheduleQueryInfo;
import com.ym.mec.common.constant.CommonConstants;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.ImGroupMember;
import com.ym.mec.common.entity.ImGroupModel;
import com.ym.mec.common.entity.ImUserModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.page.QueryInfo;
import com.ym.mec.common.redis.service.RedisCache;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateConvertor;
import com.ym.mec.util.date.DateUtil;

@Service
public class ClassGroupServiceImpl extends BaseServiceImpl<Integer, ClassGroup> implements ClassGroupService {

    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private SchoolDao schoolDao;
    @Autowired
    private VipGroupDao vipGroupDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private PracticeGroupDao practiceGroupDao;
    @Autowired
    private CoursesGroupDao coursesGroupDao;
    @Autowired
    private MusicGroupBuildLogDao musicGroupBuildLogDao;
    @Autowired
    private ClassGroupRelationService classGroupRelationService;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private ClassGroupStudentMapperService classGroupStudentMapperService;
    @Autowired
    private ClassGroupRelationDao classGroupRelationDao;
    @Autowired
    private ClassGroupTeacherMapperService classGroupTeacherMapperService;
    @Autowired
    private TeacherDefaultMusicGroupSalaryService teacherDefaultMusicGroupSalaryService;
    @Autowired
    private StudentRegistrationDao studentRegistrationDao;
    @Autowired
    private MusicGroupStudentFeeDao musicGroupStudentFeeDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private SubjectService subjectService;
    @Autowired
    private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;
    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
    private StudentAttendanceDao studentAttendanceDao;
    @Autowired
    private CourseScheduleTeacherSalaryService courseScheduleTeacherSalaryService;
    @Autowired
    private StudentRegistrationService studentRegistrationService;
    @Autowired
    private ImGroupMemberService imGroupMemberService;
    @Autowired
    private ImGroupService imGroupService;
    @Autowired
    private ImUserFriendService imUserFriendService;
    @Autowired
    private CourseScheduleService courseScheduleService;
    @Autowired
    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
    @Autowired
    private StudentApplyRefundsDao studentApplyRefundsDao;
    @Autowired
    private RedisCache<String, Object> redisCache;
    @Autowired
    private ClassGroupService classGroupService;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private GroupDao groupDao;
    @Autowired
    private CourseScheduleEvaluateDao courseScheduleEvaluateDao;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private MusicGroupPaymentCalenderCourseSettingsService musicGroupPaymentCalenderCourseSettingsService;
    @Autowired
    private OrganizationCourseUnitPriceSettingsDao organizationCourseUnitPriceSettingsDao;
    @Autowired
    private MusicGroupPaymentCalenderDao musicGroupPaymentCalenderDao;
    @Autowired
    private MusicGroupPaymentCalenderService musicGroupPaymentCalenderService;
    @Autowired
    private MusicGroupStudentClassAdjustDao musicGroupStudentClassAdjustDao;

    @Override
    public BaseDAO<Integer, ClassGroup> getDAO() {
        return classGroupDao;
    }

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

        List<ClassGroup> dataList = new ArrayList<ClassGroup>();
        int count = this.findCount(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = this.getDAO().queryPage(params);
            List<Integer> classGroupIds = dataList.stream().map(ClassGroup::getId).collect(Collectors.toList());

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

            for (ClassGroup cg : dataList) {
                Long studentNum = classGroupStudentNumMap.get(cg.getId());
                cg.setStudentNum(Objects.isNull(studentNum) ? 0 : studentNum.intValue());
                cg.setTeacherMapperList(classGroupTeacherMapperDao.findClassGroupTeachers(cg.getId() + ""));
                cg.setCourseScheduleList(courseScheduleDao.findCoursesByClassGroupId(cg.getId(), null));
            }
        }

        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean create(ClassGroup classGroup) {

        if (classGroup.getType() == null) {
            throw new BizException("班级类型不能为空");
        }
        if (classGroup.getGroupType() == null) {
            throw new BizException("课程组类型不能为空");
        }

        //基础技能班和线上基础技能班，可分班原则为声部人数/6向上取整
        if (classGroup.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE) || classGroup.getType().equals(ClassGroupTypeEnum.HIGH)) {
            HighClassGroupNumDto highClassGroupNumDto = getSubjectMaxHighClassGroupNum(classGroup.getMusicGroupId(), classGroup.getType());
            if (highClassGroupNumDto.getNowHighClassGroupNum() >= highClassGroupNumDto.getMaxHighClassGroupNum()) {
                String errMsg = classGroup.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE) ? "线上基础技能班" : "基础技能班";
                throw new BizException("此乐团，" + errMsg + "数量不能大于" + highClassGroupNumDto.getMaxHighClassGroupNum());
            }
        }

        String userIds = classGroup.getUserIds();

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

        if (StringUtils.isNotBlank(userIds)) {
            userIdStrSet = new HashSet<>(Arrays.asList(userIds.split(",")));
        }

        Date date = new Date();
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        classGroup.setStudentNum(userIdStrSet.size());
        //创建班级
        insert(classGroup);

        //设置班级上的老师
        List<Integer> teacherIdList = new ArrayList<>();
        List<ClassGroupTeacherMapper> teacherMapperList = classGroup.getTeacherMapperList();
        for (ClassGroupTeacherMapper tm : teacherMapperList) {
            tm.setClassGroupId(classGroup.getId());
            tm.setMusicGroupId(classGroup.getMusicGroupId());
            tm.setGroupType(classGroup.getGroupType());
            tm.setCreateTime(date);
            tm.setUpdateTime(date);
            teacherIdList.add(tm.getUserId());
        }

        if (teacherMapperList.size() > 0) {
            classGroupTeacherMapperDao.classGroupTeachersInsert(teacherMapperList);
        }

        //2、插入班级学生关联关系
        List<Integer> userIdList = new ArrayList<>();
        List<ClassGroupStudentMapper> classGroupStudentList = new ArrayList<>();
        for (String userId : userIdStrSet) {
            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapper.setUserId(Integer.parseInt(userId));
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(MUSIC);
            classGroupStudentList.add(classGroupStudentMapper);

            StudentRegistration studentRegistration = new StudentRegistration();
            studentRegistration.setClassGroupId(classGroup.getId());
            studentRegistration.setUserId(Integer.parseInt(userId));
            studentRegistration.setMusicGroupId(classGroup.getMusicGroupId());
            studentRegistrationDao.updateByUserIdAndMusicGroupId(studentRegistration);

            userIdList.add(Integer.parseInt(userId));
        }
        if (classGroupStudentList.size() > 0) {
            classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentList);
        }

        // 加入IM群组
        if (userIdList.size() > 0) {
            addImGroup(classGroup, userIdList, teacherIdList);
        }
        return true;
    }

    @Override
    public List<ClassGroup> findClassGroup4Teacher(Integer teacherId) {
        return classGroupDao.findClassGroup4Teacher(teacherId);
    }

    @Override
    public List<ClassGroup> findClassGroup(String musicGroupId, Integer mixClassGroupId) {
        if (null == mixClassGroupId) {
            return classGroupDao.findAllMixClassGroup(musicGroupId);
        } else {
            return classGroupDao.findMixClassChildClassGroup(mixClassGroupId);
        }
    }

    @Override
    public List<ClassGroup> findAllNormalClassGroupByMusicGroupId(String musicGroupId) {
        return classGroupDao.findAllNormalClassGroupByMusicGroupId(musicGroupId);
    }

    @Override
    public List<ClassGroup> findAllMixClassGroupByMusicGroupId(String musicGroupId) {
        List<ClassGroup> allMixClassGroup = classGroupDao.findAllMixClassGroup(musicGroupId);
        for (ClassGroup mixClassGroup : allMixClassGroup) {
            ClassGroup mixClassChildClassGroup = classGroupDao.findMixClassChildClassGroupNames(mixClassGroup.getId());
            if (mixClassChildClassGroup != null) {
                mixClassGroup.setClassNames(mixClassChildClassGroup.getName());
            }
        }
        return allMixClassGroup;
    }

    @Override
    public List<ClassGroup> findAllClassGroupByMusicGroup(String musicGroupId, String type) {
        return classGroupDao.findAllClassGroupByMusicGroup(musicGroupId, type);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup addClassGroup(ClassGroup classGroup, GroupType groupType) throws Exception {
        String userIds = classGroup.getUserIds();
        if (userIds == null || userIds.isEmpty()) throw new BizException("班级学生不能为空");

        Set<String> userIdStrSet = new HashSet<>(Arrays.asList(userIds.split(",")));

        Date date = new Date();
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        classGroup.setType(ClassGroupTypeEnum.NORMAL);
        classGroup.setGroupType(groupType);
        classGroup.setExpectStudentNum(userIdStrSet.size());
        classGroup.setStudentNum(userIdStrSet.size());
        insert(classGroup);

        //2、插入班级学生关联关系
        List<Integer> userIdList = new ArrayList<>();
        List<ClassGroupStudentMapper> classGroupStudentList = new ArrayList<>();
        for (String userId : userIdStrSet) {
            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapper.setUserId(Integer.parseInt(userId));
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(MUSIC);
            classGroupStudentList.add(classGroupStudentMapper);

            StudentRegistration studentRegistration = new StudentRegistration();
            studentRegistration.setClassGroupId(classGroup.getId());
            studentRegistration.setUserId(Integer.parseInt(userId));
            studentRegistration.setMusicGroupId(classGroup.getMusicGroupId());
            studentRegistrationDao.updateByUserIdAndMusicGroupId(studentRegistration);

            userIdList.add(Integer.parseInt(userId));
        }
        classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentList);

        //加入IM群组
        addImGroup(classGroup, userIdList, null);
        return classGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup addMixClassGroup(String musicGroupId, String name, String classGroupIds) {
        Date date;
        date = new Date();

        List<ClassGroup> classGroups = findClassGroupByIds(classGroupIds);
        int studentNum = 0; //学生数
        String subjectIds = "";
        List<Integer> classGroupIdList = new ArrayList<>();
        for (ClassGroup classGroup : classGroups) {
            studentNum += classGroup.getStudentNum();
            subjectIds += subjectIds.isEmpty() ? classGroup.getSubjectIdList() : "," + classGroup.getSubjectIdList();
            classGroupIdList.add(classGroup.getId());
        }

        //1、插入班级
        ClassGroup classGroup = new ClassGroup();
        classGroup.setMusicGroupId(musicGroupId);
        classGroup.setSubjectIdList(subjectIds);
        classGroup.setName(name);
        classGroup.setType(ClassGroupTypeEnum.MIX);
        classGroup.setGroupType(MUSIC);
        classGroup.setExpectStudentNum(studentNum);
        classGroup.setStudentNum(studentNum);
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        insert(classGroup);

        List<Integer> userIdList = new ArrayList<>();
        List<ClassGroupStudentMapper> mixClassGroupStudentMappers = new ArrayList<>();
        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findByClassGroups(classGroupIdList);

        for (ClassGroupStudentMapper classGroupStudentMapper : classGroupStudentMappers) {
            ClassGroupStudentMapper mixClassGroupStudentMapper = new ClassGroupStudentMapper();
            if (classGroupStudentMapper.getStatus().equals(ClassGroupStudentStatusEnum.QUIT)) continue;

            mixClassGroupStudentMapper.setMusicGroupId(musicGroupId);
            mixClassGroupStudentMapper.setClassGroupId(classGroup.getId());
            mixClassGroupStudentMapper.setUserId(classGroupStudentMapper.getUserId());
            mixClassGroupStudentMapper.setCreateTime(date);
            mixClassGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            mixClassGroupStudentMapper.setGroupType(MUSIC);
            mixClassGroupStudentMappers.add(mixClassGroupStudentMapper);

            userIdList.add(classGroupStudentMapper.getUserId());
        }
        //插入学生关联关系
        classGroupStudentMapperDao.classGroupStudentsInsert(mixClassGroupStudentMappers);

        //2、插入班级关联关系
        List<ClassGroupRelation> classGroupRelationList = new ArrayList<>();
        for (ClassGroup cGroup : classGroups) {
            ClassGroupRelation classGroupRelation = new ClassGroupRelation();
            classGroupRelation.setClassGroupId(classGroup.getId());
            classGroupRelation.setSubClassGroupId(cGroup.getId());
            classGroupRelation.setCreateTime(date);
            classGroupRelationList.add(classGroupRelation);
        }
        classGroupRelationService.classGroupRelationsInsert(classGroupRelationList);

        //加入IM群组
        addImGroup(classGroup, userIdList, null);

        return classGroup;
    }

    @Override
    public List<ClassGroup> findClassGroupByIds(String ids) {
        return classGroupDao.findClassGroupByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<HighClassGroupDto> addHighClassGroup(List<HighClassGroupDto> highClassGroupList) throws Exception {
        String key = "addHighClassGroup";
        long value = Thread.currentThread().getId();
        redisCache.getLocked(key, value, 30);
        try {
            MusicGroup musicGroup = musicGroupDao.get(highClassGroupList.get(0).getMusicGroupId());

            int highClassGroupNum = studentRegistrationDao.findMusicGroupStudentNum(musicGroup.getId()) / 5;
            if (highClassGroupList.size() > highClassGroupNum) {
                throw new BizException("班数不能大于" + highClassGroupNum);
            }

            List<ClassGroup> classGroups = classGroupDao.findClassGroupByMusicGroupIdAndType(musicGroup.getId(), ClassGroupTypeEnum.HIGH);
            if (classGroups.size() > 0) {
                List<Integer> classGroupIds = classGroups.stream().map(classGroup -> classGroup.getId()).collect(Collectors.toList());

                // 删除基础提高班
                classGroupDao.batchSoftDelete(classGroupIds);
                // 删除基础提高老师
                classGroupTeacherMapperDao.delClassGroupTeacherMapper(classGroupIds);

                List<CourseSchedule> classGroupNoStartCourseSchedules = courseScheduleService.findClassGroupNoStartCourseSchedules(classGroupIds,
                        MUSIC);

                if (classGroupNoStartCourseSchedules.size() > 0) {
                    List<Long> courseScheduleIds = classGroupNoStartCourseSchedules.stream().map(courseSchedule -> courseSchedule.getId())
                            .collect(Collectors.toList());
                    courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
                    teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
                    // 删除基础提高班课程
                    courseScheduleDao.deleteCourseSchedulesByClassGroupIds(courseScheduleIds);
                }

                List<ImGroupModel> imGroupModelList = new ArrayList<>();
                for (ClassGroup classGroup : classGroups) {
                    imGroupModelList.add(new ImGroupModel(classGroup.getId().toString(), null, classGroup.getName()));
                }
                //imFeignService.groupBatchDismiss(imGroupModelList);
            }

            List<CourseSchedule> courseScheduleList = new ArrayList<>();
            List<ClassGroupTeacherMapper> classGroupTeacherMapperList = new ArrayList<>();
            List<ClassGroupImGroupDto> classGroupImGroupList = new ArrayList<>();
            Integer schoolId = musicGroup.getSchoolId();

            for (HighClassGroupDto highClassGroup : highClassGroupList) {
                if (highClassGroup.getDayOfWeek() < 1 || highClassGroup.getDayOfWeek() > 7) {
                    throw new BizException("上课星期错误，请核查");
                }
                // 1、插入班级信息
                Date date;
                date = new Date();
                highClassGroup.setId(null);
                highClassGroup.setGroupType(MUSIC);
                highClassGroup.setCreateTime(date);
                highClassGroup.setUpdateTime(date);
                highClassGroup.setType(ClassGroupTypeEnum.HIGH);
                highClassGroup.setTotalClassTimes(highClassGroup.getCourseTimes());
                highClassGroup.setCurrentClassTimes(0);
                insert(highClassGroup);

                // 2、插入班级关联老师
                ClassGroupTeacherMapper classGroupTeacherMapper = new ClassGroupTeacherMapper();
                classGroupTeacherMapper.setMusicGroupId(highClassGroup.getMusicGroupId());
                classGroupTeacherMapper.setClassGroupId(highClassGroup.getId());
                classGroupTeacherMapper.setTeacherRole(TeachTypeEnum.BISHOP);
                classGroupTeacherMapper.setUserId(highClassGroup.getUserId());
                classGroupTeacherMapper.setGroupType(MUSIC);
                classGroupTeacherMapper.setCreateTime(date);
                classGroupTeacherMapper.setUpdateTime(date);
                classGroupTeacherMapperList.add(classGroupTeacherMapper);

                // 3、插入班级排课信息
                int times = 0;
                LocalDateTime now = LocalDate.parse(highClassGroup.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();

                List<Subject> subjectList = subjectService.findBySubjectByIdList(highClassGroup.getSubjectIdList());

                String courseScheduleName = subjectList.stream().map(subject -> subject.getName()).collect(Collectors.joining("/"));

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

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

                WhileNode:
                while (highClassGroup.getCourseTimes() > times) {
                    if (highClassGroup.getHoliday() && holidayDays.contains(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))) {
                        now = now.plusDays(1);
                        continue;
                    }

                    int dayOfWeek = now.getDayOfWeek().getValue();
                    if (highClassGroup.getDayOfWeek() == dayOfWeek) {
                        CourseSchedule courseSchedule = new CourseSchedule();
                        Instant instant = now.atZone(ZoneId.systemDefault()).toInstant();
                        Date classDate = Date.from(instant);
                        String startClassTime = DateUtil.getDate(classDate) + " " + highClassGroup.getStartClassTime() + ":00";
                        String endClassTime = DateUtil.getDate(classDate) + " " + highClassGroup.getEndClassTime() + ":00";

                        courseSchedule.setSchoolId(schoolId);
                        courseSchedule.setMusicGroupId(highClassGroup.getMusicGroupId());
                        courseSchedule.setClassGroupId(highClassGroup.getId());
                        courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                        courseSchedule.setClassDate(classDate);
                        courseSchedule.setStartClassTime(DateUtil.stringToDate(startClassTime));
                        courseSchedule.setEndClassTime(DateUtil.stringToDate(endClassTime));
                        courseSchedule.setTeacherId(highClassGroup.getUserId());
                        courseSchedule.setActualTeacherId(highClassGroup.getUserId());
                        courseSchedule.setCreateTime(date);
                        courseSchedule.setUpdateTime(date);
                        courseSchedule.setTeachMode(TeachModeEnum.OFFLINE);
                        courseSchedule.setType(CourseSchedule.CourseScheduleType.HIGH);
                        courseSchedule.setGroupType(MUSIC);
                        courseSchedule.setName(courseScheduleName + "-" + CourseSchedule.CourseScheduleType.HIGH.getMsg());
                        courseSchedule.setOrganId(musicGroup.getOrganId());
                        courseScheduleList.add(courseSchedule);
                        times++;
                    }
                    now = now.plusDays(1);
                }

                List<Integer> userIdList = new ArrayList<>();
                userIdList.add(classGroupTeacherMapper.getUserId());

                ClassGroupImGroupDto classGroupImGroupDto = new ClassGroupImGroupDto();
                classGroupImGroupDto.setClassGroup(highClassGroup);
                classGroupImGroupDto.setUserIds(userIdList);
                classGroupImGroupList.add(classGroupImGroupDto);
            }

            // 加入Im群组
            //batchAddImGroup(classGroupImGroupList);
            classGroupTeacherMapperService.classGroupTeachersInsert(classGroupTeacherMapperList);
            // 检测新排课冲突
            courseScheduleService.checkNewCourseSchedules(courseScheduleList, false, false);
            courseScheduleDao.batchAddCourseSchedules(courseScheduleList);
        } finally {
            redisCache.releaseLocked(key, value);
        }
        return highClassGroupList;
    }

    @Override
    public PageInfo<TeacherMusicClassInfoDto> getTeacherMusicClass(TeacherMusicClassQueryInfo queryInfo) {
        PageInfo<TeacherMusicClassInfoDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<TeacherMusicClassInfoDto> dataList = null;
        int count = classGroupDao.countGroupCourses(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupDao.queryGroupCourses(params);
            HashMap<String, Object> param = new HashMap<>();
            param.put("teacherId", queryInfo.getSearch());
            param.put("attendanceStatus", YesOrNoEnum.YES);
            Set<String> classGroupIds = dataList.stream().map(e -> e.getClassGroupIds()).collect(Collectors.toSet());
            Map<Integer, Long> hasRestClassMap = MapUtil.convertIntegerMap(courseScheduleDao.queryHasReatClass(classGroupIds, queryInfo.getSearch()));
            int teacherPersonalAttendancesCount = teacherAttendanceDao.getTeacherPersonalAttendancesCount(param);
            dataList.forEach(e -> {
                param.put("musicGroupId", e.getMusicGroupId());
                e.setAttendanceNum(teacherPersonalAttendancesCount);
                e.setHasRestClass(hasRestClassMap.get(Integer.parseInt(e.getClassGroupIds())).intValue());
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public PageInfo<TeacherVipClassInfoDto> getTeacherVipClass(VipClassQueryInfo queryInfo) {
        PageInfo<TeacherVipClassInfoDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<TeacherVipClassInfoDto> dataList = null;
        int count = vipGroupDao.countTeacherVipClass(queryInfo.getTeacherId());
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = vipGroupDao.getTeacherVipClass(params);
//            Set<Integer> activityIds = dataList.stream().map(e -> e.getActivityId()).collect(Collectors.toSet());
//            List<Map<Integer, String>> names = vipGroupActivityDao.queryNamesById(StringUtils.join(activityIds, ","));
//            Map<Integer, String> nameMap = MapUtil.convertMybatisMap(names);
            //计算月度平均消耗值(已上课时 / 消耗月份)
            List<String> vipGroupIds = dataList.stream().map(vipGroup -> String.valueOf(vipGroup.getVipClassId())).collect(Collectors.toList());
            List<Map<Long, Integer>> vipGroupOverCourses = courseScheduleDao.countGroupOverCourse(vipGroupIds, "VIP");
            Map<Long, Integer> vipGroupOverCourseMaps = MapUtil.convertIntegerMap(vipGroupOverCourses);
            dataList.forEach(vipGroup -> {
                Integer overCourses = vipGroupOverCourseMaps.get(vipGroup.getVipClassId());
                if (Objects.isNull(overCourses)) {
                    overCourses = 0;
                }
                Integer totalClassTimes = vipGroup.getTotalClassTimes();
                if (Objects.isNull(totalClassTimes)) {
                    vipGroup.setMonthAvg(Float.parseFloat("0.0"));
                } else {
                    if (overCourses <= 0) {
                        vipGroup.setMonthAvg(0);
                    } else {
                        BigDecimal overCoursesOfMonth = new BigDecimal(overCourses), allClassTimes = new BigDecimal(totalClassTimes);

                        Float monthConsumeRate = overCoursesOfMonth.divide(overCoursesOfMonth, CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP).floatValue();

                        vipGroup.setMonthAvg(monthConsumeRate);
                    }

                }
            });

        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public List<ClassGroupTeachersDto> getClassGroupAndTeachers(String musicGroupId, String type, Integer classGroupId) {
        List<ClassGroupTeachersDto> classGroupAndTeachersList = classGroupDao.findClassGroupByMusicGroupId(musicGroupId, type, classGroupId);

        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroupTeacherMapperService.findClassGroupTeachers(classGroupAndTeachersList);
        //获取当前乐团的合奏班id列表map
        HashMap<Integer, Integer> idMap = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(classGroupRelationDao.queryClassRelationIdMap(musicGroupId))), HashMap.class);
        HashMap<Integer, String> nameMap = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(classGroupRelationDao.queryClassRelationNameMap(musicGroupId))), HashMap.class);

        for (ClassGroupTeachersDto classGroupAndTeachers : classGroupAndTeachersList) {
            List<ClassGroupTeacherMapper> oneClassGroupTeacherMapperList = new ArrayList<>();
            for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
                if (classGroupTeacherMapper.getClassGroupId().equals(classGroupAndTeachers.getId())) {
                    oneClassGroupTeacherMapperList.add(classGroupTeacherMapper);
                }
            }
            classGroupAndTeachers.setMixClassName(nameMap.get(classGroupAndTeachers.getId()));
            classGroupAndTeachers.setMixClassId(idMap.get(classGroupAndTeachers.getId()));
            classGroupAndTeachers.setClassGroupTeacherMapperList(oneClassGroupTeacherMapperList);
        }
        return classGroupAndTeachersList;
    }

    @Override
    public List<ClassGroupTeachersDto> getClassGroupAndTeacherSalary(String musicGroupId, SalarySettlementTypeEnum type, Integer classGroupId) throws Exception {
        //乐团班级及班级老师
        List<ClassGroupTeachersDto> classGroupAndTeachers = getClassGroupAndTeachers(musicGroupId, "NORMAL,MIX,HIGH,HIGH_ONLINE", classGroupId);
        BigDecimal zeroSalary = new BigDecimal(0);
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (type != null) {
            musicGroup.setSettlementType(type);
            musicGroupDao.update(musicGroup);
        }
        if (classGroupAndTeachers == null || classGroupAndTeachers.size() == 0) {
            return null;
        }

        List<Integer> classGroupIds = classGroupAndTeachers.stream().map(ClassGroupTeachersDto::getId).collect(Collectors.toList());

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

        String waringStr = "";
        for (ClassGroupTeachersDto classGroupAndTeacher : classGroupAndTeachers) {
            //所有教师列表
            List<Integer> teacherUserIds = classGroupAndTeacher.getClassGroupTeacherMapperList().stream().map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toList());
            List<Teacher> teachers = teacherDao.findByTeacherIds(teacherUserIds);
            Map<Integer, Teacher> teacherMap = teachers.stream()
                    .collect(Collectors.toMap(Teacher::getId, teacher -> teacher));

            Long studentNum = classGroupStudentNumMap.get(classGroupAndTeacher.getId());
            studentNum = Objects.isNull(studentNum) ? 0 : studentNum;
            if (classGroupAndTeacher.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE) && (studentNum < 3 || studentNum > 5)) {
                String numWaring = studentNum < 3 ? "人数不能小于3，" : "人数不能大于5，";
                waringStr += classGroupAndTeacher.getName() + numWaring;
            }
            //班级的教师列表
            List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroupAndTeacher.getClassGroupTeacherMapperList();
            for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
                //获取老师的默认课酬
                String courseType = classGroupAndTeacher.getType().equals(ClassGroupTypeEnum.NORMAL) ? "SINGLE" : classGroupAndTeacher.getType().getCode();

                if (musicGroup.isClassroomLessons()) {
                    courseType = "CLASSROOM";
                }

                List<TeacherDefaultMusicGroupSalary> teacherSalaryByUserIdAndType = teacherDefaultMusicGroupSalaryService.getTeacherSalaryByUserIdAndType(classGroupTeacherMapper.getUserId(), courseType, type);
                //老师课酬没有设置，设置成0
                if (teacherSalaryByUserIdAndType == null || teacherSalaryByUserIdAndType.size() == 0) {
                    Teacher teacher = teacherMap.get(classGroupTeacherMapper.getUserId());
                    throw new BizException("请设置" + teacher.getRealName() + "老师" + classGroupAndTeacher.getType().getMsg() + "课酬");
                }

                for (TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalary : teacherSalaryByUserIdAndType) {
                    if (teacherDefaultMusicGroupSalary.getCourseScheduleType().equals(CourseSchedule.CourseScheduleType.HIGH_ONLINE) && teacherDefaultMusicGroupSalary.getSalaryRuleJson() != null) {
                        if (studentNum > 5) {
                            studentNum = Long.valueOf(5);
                        }
                        BigDecimal salary = JSON.parseObject(teacherDefaultMusicGroupSalary.getSalaryRuleJson()).getBigDecimal(studentNum.toString());
                        teacherDefaultMusicGroupSalary.setMainTeacher30MinSalary(salary);
                        teacherDefaultMusicGroupSalary.setMainTeacher90MinSalary(salary);
                    }
                }
                classGroupTeacherMapper.setTeacherDefaultMusicGroupSalaryList(teacherSalaryByUserIdAndType);
            }

        }
        if (!waringStr.isEmpty()) {
            throw new BizException(waringStr + "请调整");
        }
        return classGroupAndTeachers;
    }

    @Override
    public PageInfo<CourseListDto> queryCoursePage(UserMusicGroupQueryInfo queryInfo, Integer userId) {
        queryInfo.setSearch(userId.toString());
        PageInfo<CourseListDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        params.put("userId", userId);
        List<CourseListDto> courseListDtos = null;
        //获取分页前的所有的乐团编号和vip编号
        params.put("offset", pageInfo.getOffset());
        List<String> musicGroupIds = null;
        List<Group> groups;
        if (queryInfo.isHideOverGroup()) {
            groups = courseScheduleDao.queryMusicGroupIdsWithoutOverGroup(params);
            pageInfo.setTotal(courseScheduleDao.countMusicGroupIdsWithoutOverGroup(params));
        } else {
            groups = courseScheduleDao.queryMusicGroupIds(params);
            pageInfo.setTotal(courseScheduleDao.countMusicGroupIds(params));
        }
        Map<GroupType, List<Group>> typeGroupMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(groups)) {
            typeGroupMap = groups.stream().collect(Collectors.groupingBy(Group::getGroupType));
        }
        courseListDtos = new ArrayList<>();
        if (!CollectionUtils.isEmpty(typeGroupMap.get(GroupType.VIP))) {
            musicGroupIds = typeGroupMap.get(GroupType.VIP).stream().map(Group::getId).collect(Collectors.toList());
        }
        //获取学员所购买的vip课列表详情
        List<CourseListDto> vipCourses = classGroupDao.queryStudentVipCourses(StringUtils.join(musicGroupIds, ","), userId);
        //获取vip课的学生列表
        Set<String> vipIds = vipCourses.stream().map(CourseListDto::getVipId).collect(Collectors.toSet());
        Map<String, String> vipStuNames = MapUtil.convertIntegerMap(classGroupDao.findVipStuNames(StringUtils.join(vipIds, ","), "VIP"));

        if (!CollectionUtils.isEmpty(typeGroupMap.get(MUSIC))) {
            musicGroupIds = typeGroupMap.get(MUSIC).stream().map(Group::getId).collect(Collectors.toList());
        } else {
            musicGroupIds = null;
        }
        //获取学员的乐团列表详情
        List<CourseListDto> musicCourse = classGroupDao.queryStudentMusicGroupCourses(StringUtils.join(musicGroupIds, ","), userId);

        if (!CollectionUtils.isEmpty(typeGroupMap.get(PRACTICE))) {
            musicGroupIds = typeGroupMap.get(PRACTICE).stream().map(Group::getId).collect(Collectors.toList());
        } else {
            musicGroupIds = null;
        }
        //获取学员购买的陪练课列表
        List<CourseListDto> practiceCourse = classGroupDao.queryStudentPracticeCourses(StringUtils.join(musicGroupIds, ","));
        Set<String> practiceGroupId = practiceCourse.stream().map(e -> e.getPracticeId()).collect(Collectors.toSet());
        //获取陪练课学生名字
        Map<String, String> practiceStuNames = MapUtil.convertIntegerMap(classGroupDao.findVipStuNames(StringUtils.join(practiceGroupId, ","), "PRACTICE"));
        //获取有陪练报告的课程组
        List<Integer> classGroupIds = practiceCourse.stream().map(e -> e.getClassGroupId()).collect(Collectors.toList());
        List<CourseScheduleEvaluate> courseScheduleEvaluates = new ArrayList<>();
        if (classGroupIds.size() > 0) {
            courseScheduleEvaluates = courseScheduleEvaluateDao.findByClassGroupIds(classGroupIds);
        }
        Map<Integer, List<CourseScheduleEvaluate>> reportMap = new HashMap<>();
        if (courseScheduleEvaluates.size() > 0) {
            reportMap = courseScheduleEvaluates.stream().collect(Collectors.groupingBy(CourseScheduleEvaluate::getClassGroupId));
        }

        Set<String> musicGroupId = musicCourse.stream().map(e -> e.getMusicId()).collect(Collectors.toSet());
//        Set<String> vipGroupId = vipCourses.stream().map(e -> e.getVipId()).collect(Collectors.toSet());

        Map<String, Long> musicCourseNumMap = new HashMap<>();
        if (musicGroupId != null && musicGroupId.size() > 0) {
            musicCourseNumMap = MapUtil.convertIntegerMap(courseScheduleStudentPaymentDao.findStudentCourseNum(musicGroupId, userId, "MUSIC"));
        }
        Map<String, Long> vipCourseNumMap = new HashMap<>();
        if (vipIds != null && vipIds.size() > 0) {
            vipCourseNumMap = MapUtil.convertIntegerMap(courseScheduleStudentPaymentDao.findStudentCourseNum(vipIds, userId, "VIP"));
        }
        Map<String, Long> practiceCourseNumMap = new HashMap<>();
        if (practiceGroupId != null && practiceGroupId.size() > 0) {
            practiceCourseNumMap = MapUtil.convertIntegerMap(courseScheduleStudentPaymentDao.findStudentCourseNum(practiceGroupId, userId, "PRACTICE"));
        }
        courseListDtos.addAll(musicCourse);
        courseListDtos.addAll(vipCourses);
        courseListDtos.addAll(practiceCourse);
        //检测对应乐团是否已申请退费
        List<Map<String, Integer>> isApplyMaps;
        if (!CollectionUtils.isEmpty(typeGroupMap.get(MUSIC))) {
            musicGroupIds = typeGroupMap.get(MUSIC).stream().map(Group::getId).collect(Collectors.toList());
        } else {
            musicGroupIds = null;
        }
        if (musicGroupIds != null && musicGroupIds.size() > 0) {
            isApplyMaps = studentApplyRefundsDao.checkIsApplyRefund(musicGroupIds, userId);
        } else {
            isApplyMaps = new ArrayList<>();
        }
        Map<String, Integer> isApplyMap = MapUtil.convertIntegerMap(isApplyMaps);
        //获取所有教学点名称列表
        Set<Integer> schoolIds = courseListDtos.stream().map(CourseListDto::getTeacherSchoolId).collect(Collectors.toSet());
        Map<Integer, String> schoolNames = MapUtil.convertMybatisMap(schoolDao.queryNameByIds(StringUtils.join(schoolIds, ",")));

        SysConfig practiceRenewUrlConfig = sysConfigService.findByParamName(SysConfigService.PRACTICE_RENEW_URL);

        Long classTimes = null;
        for (CourseListDto e : courseListDtos) {
            if (StringUtils.isNotEmpty(e.getMusicId())) {
                classTimes = musicCourseNumMap.get(e.getMusicId());
            } else if (StringUtils.isNotEmpty(e.getVipId())) {
                classTimes = vipCourseNumMap.get(e.getVipId());
            } else if (StringUtils.isNotEmpty(e.getPracticeId())) {
                classTimes = practiceCourseNumMap.get(e.getPracticeId());
            }
            e.setSurplusClassTimes(classTimes == null ? 0 : classTimes.intValue());

            e.setAddress(schoolNames.get(e.getTeacherSchoolId()));
            e.setIsApply(isApplyMap.get(e.getMusicId()));
            if (ClassGroupTypeEnum.PRACTICE == e.getType()) {
                e.setStudentNames(practiceStuNames.get(e.getPracticeId()));
                e.setPracticeRenewUrl(practiceRenewUrlConfig.getParanValue() + e.getPracticeId());
                if (reportMap.containsKey(e.getClassGroupId())) {
                    List<CourseScheduleEvaluate> classGroupCourseScheduleEvaluates = reportMap.get(e.getClassGroupId());
                    CourseScheduleEvaluate courseScheduleEvaluate = classGroupCourseScheduleEvaluates.get(classGroupCourseScheduleEvaluates.size() - 1);
                    e.setHasReport(true);
                    String baseUrl = sysConfigDao.findConfigValue(SysConfigService.BASE_API_URL);
                    if (courseScheduleEvaluate.getVersion().equals(1)) {
                        e.setStudyReportUrl(baseUrl + "/#/reportDetail?classGroupId=" + e.getClassGroupId());
                    } else if (courseScheduleEvaluate.getVersion().equals(2)) {
                        e.setStudyReportUrl(baseUrl + "/#/reportDetailNew?id=" + courseScheduleEvaluate.getId() + "&classGroupId=" + e.getClassGroupId());
                    }
                }
            }
            if (ClassGroupTypeEnum.VIP == e.getType()) {
                e.setStudentNames(vipStuNames.get(e.getVipId()));
                //1：线上；2：线下；3：线上+线下
                if (e.getOnlineClassesNum() > 0 && e.getOffLineClassesNum() <= 0) {
                    e.setClassMode(1);
                } else if (e.getOnlineClassesNum() > 0 && e.getOffLineClassesNum() > 0) {
                    e.setClassMode(3);
                } else if (e.getOnlineClassesNum() <= 0 && e.getOffLineClassesNum() > 0) {
                    e.setClassMode(2);
                } else {
                    e.setClassMode(0);
                }
            }
        }
        pageInfo.setRows(courseListDtos);
        return pageInfo;
    }

    @Override
    public List<ImGroupModel> queryUserGroups(Integer userId, String search) {
        List<ImGroupModel> imGroupModels = classGroupDao.queryUserMusicGroups(userId, search);
        imGroupModels.addAll(classGroupDao.queryUserVipGroups(userId, search));
        imGroupModels.addAll(classGroupDao.queryUserCommGroups(userId, search));
        if (imGroupModels != null && imGroupModels.size() > 0) {
            imGroupModels.forEach(e -> {
                e.setCount(classGroupService.findGroupUsers(Integer.parseInt(e.getId()), null).size());
            });
        }
        return imGroupModels;
    }

    @Override
    public List<ImUserModel> findGroupUsers(Integer groupId, String search) {
        //获取相关学员
        List<ImUserModel> students = classGroupDao.findGroupUsers(groupId, search);
        if (students == null) {
            students = new ArrayList<>();
        }
        ClassGroup classGroup = classGroupDao.get(groupId);
        GroupType groupType = classGroup.getGroupType();
        String musicGroupId = classGroup.getMusicGroupId();
        //获取当前群关联的乐团
        MusicGroup musicGroup = musicGroupDao.findByClassId(groupId);
        Set<Integer> teacherIds = new HashSet<>();
        if (musicGroup != null) {
            teacherIds.add(musicGroup.getTeamTeacherId());
            teacherIds.add(musicGroup.getEducationalTeacherId());
            teacherIds.add(musicGroup.getDirectorUserId());
        }
        //获取相关老师
        teacherIds.addAll(classGroupDao.findGroupTeacher(groupId));
        //获取网管课课程教务老师
        PracticeGroup practiceGroup = null;
        VipGroup vipGroup = null;
        CoursesGroup coursesGroup = null;
        switch (groupType) {
            case PRACTICE:
                practiceGroup = practiceGroupDao.get(Long.parseLong(musicGroupId));
                teacherIds.add(practiceGroup.getEducationalTeacherId());
                break;
            case COMM:
                coursesGroup = coursesGroupDao.get(Long.parseLong(musicGroupId));
                teacherIds.add(coursesGroup.getEducationalTeacherId());
                break;
            case VIP:
                vipGroup = vipGroupDao.get(Long.parseLong(musicGroupId));
                teacherIds.add(vipGroup.getEducationalTeacherId());
                break;
        }
        teacherIds.removeAll(Collections.singleton(null));
        if (teacherIds.size() > 0) {
            List<ImUserModel> userModels = teacherDao.queryTeacherImModel(teacherIds, search);
            for (ImUserModel e : userModels) {
                if (musicGroup != null) {
                    if (musicGroup.getTeamTeacherId() != null && Integer.parseInt(e.getId()) == musicGroup.getTeamTeacherId()) {
                        e.setTitle("运营主管");
                    } else if (musicGroup.getEducationalTeacherId() != null && Integer.parseInt(e.getId()) == musicGroup.getEducationalTeacherId()) {
                        e.setTitle("乐团主管");
                    } else if (musicGroup.getDirectorUserId() != null && Integer.parseInt(e.getId()) == musicGroup.getDirectorUserId()) {
                        e.setTitle("乐队指导");
                    } else if (courseScheduleTeacherSalaryDao.isTeacher(groupId, Integer.parseInt(e.getId()))) {
                        e.setTitle("指导老师");
                    }
                } else {
                    if (groupType == PRACTICE && practiceGroup.getEducationalTeacherId() != null && Integer.parseInt(e.getId()) == practiceGroup.getEducationalTeacherId()) {
                        e.setTitle("乐团主管");
                    } else if (groupType == VIP && vipGroup.getEducationalTeacherId() != null && Integer.parseInt(e.getId()) == vipGroup.getEducationalTeacherId()) {
                        e.setTitle("乐团主管");
                    } else if (groupType == COMM && coursesGroup.getEducationalTeacherId() != null && Integer.parseInt(e.getId()) == coursesGroup.getEducationalTeacherId()) {
                        e.setTitle("乐团主管");
                    } else if (courseScheduleTeacherSalaryDao.isTeacher(groupId, Integer.parseInt(e.getId()))) {
                        e.setTitle("指导老师");
                    }
                }
            }
            ;
            students.addAll(userModels);
        }
        return students;
    }

    @Override
    public List<ImUserModel> findGroupStudents(Integer groupId, String search) {
        return classGroupDao.findGroupUsers(groupId, search);
    }

    @Override
    public PageInfo<StudentPayInfoDto> queryStudentPayLog(StudentPayLogQueryInfo queryInfo) {
        PageInfo<StudentPayInfoDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<StudentPayInfoDto> dataList = null;
        int count = classGroupDao.countStudentPayLog(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupDao.queryStudentPayLog(params);
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup addStudent(ClassGroup classGroup, Integer userId, GroupType groupType) {
        Date date = new Date();
        //1、增加班级人数
        classGroup.setCreateTime(date);
        if (classGroupDao.addStudentNum(classGroup) <= 0) {
            throw new BizException("报名失败，请重试");
        }
        //2、插入关联关系
        ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
        classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
        classGroupStudentMapper.setClassGroupId(classGroup.getId());
        classGroupStudentMapper.setUserId(userId);
        classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
        classGroupStudentMapper.setGroupType(groupType);
        classGroupStudentMapper.setCreateTime(date);
        classGroupStudentMapperDao.insert(classGroupStudentMapper);

        //3、学生加入级未开始课程
        List<CourseSchedule> courseScheduleList = courseScheduleService.findNoStartCoursesByClassGroupId(classGroup.getId());
        BigDecimal coursePrice = new BigDecimal("0");
        List<CourseScheduleStudentPayment> courseScheduleStudentPayments = new ArrayList<>();
        for (CourseSchedule courseSchedule : courseScheduleList) {
            CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
            courseScheduleStudentPayment.setGroupType(classGroup.getGroupType());
            courseScheduleStudentPayment.setMusicGroupId(classGroup.getMusicGroupId());
            courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
            courseScheduleStudentPayment.setUserId(userId);
            courseScheduleStudentPayment.setExpectPrice(coursePrice);
            courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
            courseScheduleStudentPayment.setCreateTime(date);
            courseScheduleStudentPayment.setUpdateTime(date);
            courseScheduleStudentPayments.add(courseScheduleStudentPayment);
        }

        if (courseScheduleStudentPayments.size() != 0) {
            courseScheduleStudentPaymentService.batchInsert(courseScheduleStudentPayments);
        }

        List<Long> courseScheduleIds = courseScheduleList.stream().map(CourseSchedule::getId).collect(Collectors.toList());
        //4、调整线上基础技能班未上课课酬
        List<ClassGroupTeacherMapper> classGroupTeachers = classGroupTeacherMapperService.getClassGroupTeachers(classGroup.getId());
        int hasTeacherSalaryCount = 0;
        if (courseScheduleIds.size() > 0) {
            hasTeacherSalaryCount = courseScheduleTeacherSalaryDao.getHasTeacherSalaryCount(courseScheduleIds);
        }
        if (classGroup.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE) && hasTeacherSalaryCount > 0) {
            Integer studentNum = classGroup.getStudentNum() + 1;
            List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = new ArrayList<>();
            courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
            for (CourseSchedule courseSchedule : courseScheduleList) {
                for (ClassGroupTeacherMapper classGroupTeacher : classGroupTeachers) {
                    List<TeacherDefaultMusicGroupSalary> teacherSalaryList = teacherDefaultMusicGroupSalaryService.getTeacherSalaryByUserIdAndType(classGroupTeacher.getUserId(), ClassGroupTypeEnum.HIGH_ONLINE.getCode(), null);
                    Map<CourseSchedule.CourseScheduleType, TeacherDefaultMusicGroupSalary> collect = teacherSalaryList.stream().collect(Collectors.toMap(TeacherDefaultMusicGroupSalary::getCourseScheduleType, teacherDefaultMusicGroupSalary -> teacherDefaultMusicGroupSalary));
                    TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalary = collect.get(courseSchedule.getType());
                    if (studentNum > 5) {
                        studentNum = 5;
                    }
                    BigDecimal salary = JSON.parseObject(teacherDefaultMusicGroupSalary.getSalaryRuleJson()).getBigDecimal(studentNum.toString());

                    CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                    courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
                    courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
                    courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
                    courseScheduleTeacherSalary.setTeacherRole(classGroupTeacher.getTeacherRole());
                    courseScheduleTeacherSalary.setUserId(classGroupTeacher.getUserId());
                    courseScheduleTeacherSalary.setExpectSalary(salary);
                    courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
                    courseScheduleTeacherSalary.setCreateTime(date);
                    courseScheduleTeacherSalary.setUpdateTime(date);
                    courseScheduleTeacherSalaryList.add(courseScheduleTeacherSalary);
                }
            }
            courseScheduleTeacherSalaryService.batchInsert(courseScheduleTeacherSalaryList);
        }

        //5、加入班级群组
        imGroupMemberService.join(classGroup.getId().longValue(), userId, null, false);

        return classGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addStudentToClassGroupAndCourseArranging(Integer studentId, String classGroupIdListStr,
                                                            String batchNo,
                                                            List<MusicGroupPaymentCalenderCourseSettings> musicGroupPaymentCalenderCourseSettingsList) {

        //如果学员已经在某些班级，
        Boolean isExistClassGroup = classGroupStudentMapperDao.existByClassGroupIds(classGroupIdListStr, studentId);
        if (isExistClassGroup) {
            return true;
        }
        List<ClassGroup> classGroupList = classGroupDao.findClassGroupByIds(classGroupIdListStr);
        if (classGroupList == null || classGroupList.size() == 0) {
            throw new BizException("班级查询失败");
        }

        Date date = new Date();
        List<CourseScheduleStudentPayment> courseScheduleStudentPayments = new ArrayList<CourseScheduleStudentPayment>();

        // 计算单价
        Map<CourseScheduleType, BigDecimal> unitPriceMap = new HashMap<CourseSchedule.CourseScheduleType, BigDecimal>();
        Map<CourseScheduleType, BigDecimal> originUnitPriceMap = new HashMap<CourseSchedule.CourseScheduleType, BigDecimal>();
        Map<CourseScheduleType, BigDecimal> totalCurrentPriceMap = new HashMap<CourseSchedule.CourseScheduleType, BigDecimal>();
        Map<CourseScheduleType, BigDecimal> totalOriginPriceMap = new HashMap<CourseSchedule.CourseScheduleType, BigDecimal>();
        for (MusicGroupPaymentCalenderCourseSettings musicGroupPaymentCalenderCourseSettings : musicGroupPaymentCalenderCourseSettingsList) {
            unitPriceMap.put(
                    musicGroupPaymentCalenderCourseSettings.getCourseType(),
                    musicGroupPaymentCalenderCourseSettings.getCourseCurrentPrice().divide(
                            new BigDecimal(musicGroupPaymentCalenderCourseSettings.getCourseTotalMinuties()), CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_DOWN));

            originUnitPriceMap.put(
                    musicGroupPaymentCalenderCourseSettings.getCourseType(),
                    musicGroupPaymentCalenderCourseSettings.getCourseOriginalPrice().divide(
                            new BigDecimal(musicGroupPaymentCalenderCourseSettings.getCourseTotalMinuties()), CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_DOWN));

            totalCurrentPriceMap.put(musicGroupPaymentCalenderCourseSettings.getCourseType(), musicGroupPaymentCalenderCourseSettings.getCourseCurrentPrice());
            totalOriginPriceMap.put(musicGroupPaymentCalenderCourseSettings.getCourseType(), musicGroupPaymentCalenderCourseSettings.getCourseOriginalPrice());
        }

        Map<CourseScheduleType, BigDecimal> totalPriceMap = new HashMap<CourseSchedule.CourseScheduleType, BigDecimal>();
        Map<CourseScheduleType, BigDecimal> totalOrignPriceMap = new HashMap<CourseSchedule.CourseScheduleType, BigDecimal>();

        BigDecimal unitPrice = new BigDecimal(0);
        BigDecimal originUnitPrice = new BigDecimal(0);
        CourseScheduleType courseType = null;
        for (ClassGroup classGroup : classGroupList) {
            // 1、增加班级人数
            classGroupDao.addStudentNum(classGroup);

            // 2、插入关联关系
            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapper.setUserId(studentId);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(classGroup.getGroupType());
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapperDao.insert(classGroupStudentMapper);

            // 3、学生加入级未开始课程
            List<CourseSchedule> courseScheduleList = courseScheduleService.findNoStartCoursesByClassGroupId(classGroup.getId());
            for (CourseSchedule courseSchedule : courseScheduleList) {
                CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
                courseScheduleStudentPayment.setCourseSchedule(courseSchedule);
                courseScheduleStudentPayment.setGroupType(classGroup.getGroupType());
                courseScheduleStudentPayment.setMusicGroupId(classGroup.getMusicGroupId());
                courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
                courseScheduleStudentPayment.setUserId(studentId);
                courseScheduleStudentPayment.setBatchNo(batchNo);

                unitPrice = unitPriceMap.get(courseSchedule.getType());
                if (unitPrice != null) {
                    courseType = courseSchedule.getType();
                    BigDecimal duration = new BigDecimal(DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime()));
                    courseScheduleStudentPayment.setExpectPrice(unitPrice.multiply(duration).setScale(2, BigDecimal.ROUND_DOWN));

                    if (totalPriceMap.containsKey(courseType)) {
                        totalPriceMap.put(courseType, totalPriceMap.get(courseType).add(courseScheduleStudentPayment.getExpectPrice()));
                    } else {
                        totalPriceMap.put(courseType, courseScheduleStudentPayment.getExpectPrice());
                    }
                }

                originUnitPrice = originUnitPriceMap.get(courseSchedule.getType());
                if (originUnitPrice != null) {
                    courseType = courseSchedule.getType();
                    BigDecimal duration = new BigDecimal(DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime()));
                    courseScheduleStudentPayment.setOriginalPrice(originUnitPrice.multiply(duration).setScale(2, BigDecimal.ROUND_DOWN));

                    if (totalOrignPriceMap.containsKey(courseType)) {
                        totalOrignPriceMap.put(courseType, totalOrignPriceMap.get(courseType).add(courseScheduleStudentPayment.getOriginalPrice()));
                    } else {
                        totalOrignPriceMap.put(courseType, courseScheduleStudentPayment.getOriginalPrice());
                    }
                }
                courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
                courseScheduleStudentPayment.setCreateTime(date);
                courseScheduleStudentPayment.setUpdateTime(date);
                courseScheduleStudentPayments.add(courseScheduleStudentPayment);
            }

            //4、调整未上课课酬
            List<ClassGroupTeacherMapper> classGroupTeachers = classGroupTeacherMapperService.getClassGroupTeachers(classGroup.getId());
            if ((classGroup.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE) || classGroup.getType().equals(ClassGroupTypeEnum.HIGH)) && courseScheduleList.size() > 0) {
                Date nowDate = new Date();
                List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = new ArrayList<>();
                List<Long> courseScheduleIds = courseScheduleList.stream().map(CourseSchedule::getId).collect(Collectors.toList());
                courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
                for (CourseSchedule courseSchedule : courseScheduleList) {
                    for (ClassGroupTeacherMapper classGroupTeacher : classGroupTeachers) {
                        List<TeacherDefaultMusicGroupSalary> teacherSalaryList = teacherDefaultMusicGroupSalaryService.getTeacherSalaryByUserIdAndType(classGroupTeacher.getUserId(), ClassGroupTypeEnum.HIGH_ONLINE.getCode(), null);
                        if (teacherSalaryList == null || teacherSalaryList.size() == 0) {
                            throw new BizException("请设置老师线上网管课课酬");
                        }
                        Map<CourseSchedule.CourseScheduleType, TeacherDefaultMusicGroupSalary> collect = teacherSalaryList.stream().collect(Collectors.toMap(TeacherDefaultMusicGroupSalary::getCourseScheduleType, teacherDefaultMusicGroupSalary -> teacherDefaultMusicGroupSalary));
                        TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalary = collect.get(CourseSchedule.CourseScheduleType.HIGH_ONLINE);

                        int studentNum = classGroup.getStudentNum() + 1;
                        if (studentNum > 5) {
                            studentNum = 5;
                        }

                        BigDecimal salary = JSON.parseObject(teacherDefaultMusicGroupSalary.getSalaryRuleJson()).getBigDecimal(studentNum + "");

                        CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                        courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
                        courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
                        courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
                        courseScheduleTeacherSalary.setTeacherRole(classGroupTeacher.getTeacherRole());
                        courseScheduleTeacherSalary.setUserId(classGroupTeacher.getUserId());
                        courseScheduleTeacherSalary.setExpectSalary(salary);
                        courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
                        courseScheduleTeacherSalary.setCreateTime(nowDate);
                        courseScheduleTeacherSalary.setUpdateTime(nowDate);
                        courseScheduleTeacherSalaryList.add(courseScheduleTeacherSalary);
                    }
                }
                courseScheduleTeacherSalaryService.batchInsert(courseScheduleTeacherSalaryList);
            }

            // 5、加入班级群组
            imGroupMemberService.join(classGroup.getId().longValue(), studentId, null, false);

        }

        if (courseScheduleStudentPayments.size() > 0) {
            // 排序
            Collections.sort(courseScheduleStudentPayments);
            List<CourseScheduleType> list = new ArrayList<CourseSchedule.CourseScheduleType>();
            for (CourseScheduleStudentPayment courseScheduleStudentPayment : courseScheduleStudentPayments) {
                courseType = courseScheduleStudentPayment.getCourseSchedule().getType();
                if (!list.contains(courseType)) {
                    list.add(courseType);

                    // 修改第一节课的金额
                    courseScheduleStudentPayment.setExpectPrice(courseScheduleStudentPayment.getExpectPrice().add(
                            totalCurrentPriceMap.get(courseType).subtract(totalPriceMap.get(courseType))));

                    courseScheduleStudentPayment.setOriginalPrice(courseScheduleStudentPayment.getOriginalPrice().add(
                            totalOriginPriceMap.get(courseType).subtract(totalOrignPriceMap.get(courseType))));
                }
            }
            courseScheduleStudentPaymentService.batchInsert(courseScheduleStudentPayments);
            studentDao.updateStudentServiceTag(studentId,null,YesOrNoEnum.YES.getCode());
        }

        return true;
    }

    @Override
    public List<ClassGroup> findNoClassSubjects(String musicGroupId) {
        return classGroupDao.findNoClassSubjects(musicGroupId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delSingle(Integer classGroupId) {
        ClassGroup classGroup = classGroupDao.get(classGroupId);

        //删除学员班级关联关系
        classGroupStudentMapperDao.deleteByClassId(classGroupId);
        studentRegistrationDao.deleteClassGroup(classGroupId);

        //删除班级跟合奏班关系
        if (classGroup.getType().equals(ClassGroupTypeEnum.MIX)) { //合奏班
            classGroupRelationDao.deleteByClassId(classGroupId);
        } else {
            classGroupRelationDao.deleteBySubClassId(classGroupId);
        }

        //删除班级未开始课程
        List<CourseSchedule> courseScheduleList = courseScheduleService.findNoStartCoursesByClassGroupId(classGroupId);
        if (courseScheduleList.size() > 0) {
            List<Long> courseScheduleIds = courseScheduleList.stream().map(courseSchedule -> courseSchedule.getId()).collect(Collectors.toList());
            courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
            courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
            teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
            courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
        }

        //删除班级
        classGroupDao.delete(classGroupId);
        //删除im群组
        imGroupService.cancel(classGroupId.longValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delMix(Integer classGroupId) {
        //删除学员班级关联关系
        classGroupStudentMapperDao.deleteByClassId(classGroupId);
        //删除班级关系
        classGroupRelationDao.deleteByClassId(classGroupId);
        //删除班级未开始课程
        List<CourseSchedule> courseScheduleList = courseScheduleService.findNoStartCoursesByClassGroupId(classGroupId);
        if (courseScheduleList.size() > 0) {
            List<Long> courseScheduleIds = courseScheduleList.stream().map(courseSchedule -> courseSchedule.getId()).collect(Collectors.toList());
            courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
            courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
            teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
            courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
        }
        //删除合奏班
        classGroupDao.delete(classGroupId);
        //删除im群组
        imGroupService.cancel(classGroupId.longValue());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addMusicGroupTeam(Integer teacherId, String musicGroupId, Integer improventClassesNum) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团信息不存在");
        }
        if (musicGroup.getStatus() != MusicGroupStatusEnum.PREPARE) {
            throw new BizException("当前乐团状态不允许此操作");
        }
        //所有学员都已经分配
        List<StudentRegistration> students = studentRegistrationDao.getNoClassStuBySubjectId(musicGroupId, null);
        if (students != null && students.size() > 0) {
            throw new BizException("还有学员未分配班级");
        }
        //所有单技班都有合奏班
        List<ClassGroup> classGroupList = classGroupDao.findNoClassSubjects(musicGroupId);
        if (classGroupList != null && classGroupList.size() > 0) {
            throw new BizException("还有单技班未分配合奏");
        }
        //设置教学主管
        musicGroup.setDirectorUserId(teacherId);
        musicGroup.setImproventClassesNum(improventClassesNum);
        musicGroup.setUpdateTime(new Date());
        musicGroupDao.update(musicGroup);
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "成团确认（学员、班级、教学主管已设置）", sysUser.getId(), ""));
    }

    @Override
    public List<TeacherClassGroupDto> findTeacherClassGroups(String type,String status) {
        SysUser user = sysUserFeignService.queryUserInfo();
        if (Objects.isNull(user)) {
            throw new BizException("请登录");
        }

        if (StringUtils.isBlank(type)) {
            throw new BizException("请指定课程类型");
        }

        List<TeacherClassGroupDto> teacherMusicClassGroup;
        switch (type) {
            case "VIP":
                teacherMusicClassGroup = classGroupDao.findTeacherVipClassGroup(user.getId().longValue(),status);
                break;
            case "MUSIC_GROUP":
                teacherMusicClassGroup = classGroupDao.findTeacherMusicClassGroup(user.getId().longValue());
                break;
            case "PRACTICE":
                teacherMusicClassGroup = classGroupDao.findTeacherPracticeClassGroup(user.getId().longValue(),status);
                break;
            default:
                throw new BizException("课程类型错误");
        }
        if (CollectionUtils.isEmpty(teacherMusicClassGroup)) {
            return teacherMusicClassGroup;
        }

        List<String> subjectIdsList = teacherMusicClassGroup.stream().map(teacherClassGroupDto -> teacherClassGroupDto.getSubjectIdList()).collect(Collectors.toList());
        Map<Long, String> subjectMapBySubjectIdsList = subjectService.findSubjectMapBySubjectIdsList(subjectIdsList);

        List<String> musicGroupIds = teacherMusicClassGroup.stream().map(teacherClassGroupDto -> String.valueOf(teacherClassGroupDto.getMusicGroupId())).collect(Collectors.toList());

        List<Integer> classGroupIds = teacherMusicClassGroup.stream().map(teacherClassGroupDto -> teacherClassGroupDto.getClassGroupId().intValue()).collect(Collectors.toList());

        //统计连续旷课的人数
        List<Map<Long, Integer>> musicGroupIdAndNumList = musicGroupStudentFeeDao.countContinuosAbsenteeismStudentNum(musicGroupIds);
        Map<Long, Integer> musicGroupIdAndNum = MapUtil.convertIntegerMap(musicGroupIdAndNumList);

        List<Map<Long, Integer>> vipGroupOverCourses = courseScheduleDao.countGroupOverCourse(musicGroupIds, "VIP");
        Map<Long, Integer> vipGroupOverCourseMaps = MapUtil.convertIntegerMap(vipGroupOverCourses);

        List<ClassGroupTeacherMapper> bishopTeachers = classGroupTeacherMapperDao.findByClassGroupIdsAndType(classGroupIds, "BISHOP");
        Map<Integer, Integer> classGroupTeacherMap = bishopTeachers.stream().collect(Collectors.toMap(ClassGroupTeacherMapper::getClassGroupId, ClassGroupTeacherMapper::getUserId));
//        Map<Integer, ClassGroup> classGorupIdMap = byClassGroupIds.stream().collect(Collectors.toMap(ClassGroup::getId, classGroup -> classGroup));

        //统计班级人数
        List<Map<Integer, Integer>> classGroupStudentNumMaps = classGroupStudentMapperDao.countClassGroupsStudentNum(classGroupIds, null);
        Map<Integer, Long> classGroupStudentNumMap = MapUtil.convertIntegerMap(classGroupStudentNumMaps);
        Map<Integer, Long> currentClassTimes;
        Map<Integer, Long> noStartClassTimes = MapUtil.convertIntegerMap(courseScheduleDao.countCurrentNumByClassGroupId(classGroupIds, null));
        if (!type.equals(MUSIC)) {
            currentClassTimes = noStartClassTimes;
        } else {
            currentClassTimes = MapUtil.convertIntegerMap(courseScheduleDao.countCurrentNumByClassGroupId(classGroupIds, user.getId()));
        }


        teacherMusicClassGroup.forEach(teacherClassGroupDto -> {
            if (teacherClassGroupDto.getType() == ClassGroupTypeEnum.PRACTICE) {
                String[] studentNums = classGroupStudentMapperDao.findStudentNumByClassGroupId(teacherClassGroupDto.getClassGroupId());
                teacherClassGroupDto.setStudentNames(StringUtils.join(studentNums, ","));
            }
            if (teacherClassGroupDto.getType() == ClassGroupTypeEnum.VIP) {
                String[] studentNums = classGroupStudentMapperDao.findStudentNumByClassGroupId(teacherClassGroupDto.getClassGroupId());
                teacherClassGroupDto.setStudentNames(StringUtils.join(studentNums, ","));
                if (teacherClassGroupDto.getOnlineClassesNum() > 0 && teacherClassGroupDto.getOffLineClassesNum() <= 0) {
                    teacherClassGroupDto.setClassMode(1);
                } else if (teacherClassGroupDto.getOnlineClassesNum() > 0 && teacherClassGroupDto.getOffLineClassesNum() > 0) {
                    teacherClassGroupDto.setClassMode(3);
                } else if (teacherClassGroupDto.getOnlineClassesNum() <= 0 && teacherClassGroupDto.getOffLineClassesNum() > 0) {
                    teacherClassGroupDto.setClassMode(2);
                } else {
                    teacherClassGroupDto.setClassMode(0);
                }

                Integer overCourses = vipGroupOverCourseMaps.get(teacherClassGroupDto.getMusicGroupId());
                if (Objects.isNull(overCourses)) {
                    overCourses = 0;
                }
                Integer totalClassTimes = teacherClassGroupDto.getTotalClassTimes();
                if (Objects.isNull(totalClassTimes) || totalClassTimes == 0) {
                    teacherClassGroupDto.setAvgClassTimesOfMonth(0.0);
                } else {
                    BigDecimal overCoursesOfMonth = new BigDecimal(overCourses), allClassTimes = new BigDecimal(totalClassTimes);

                    Double monthConsumeRate = overCoursesOfMonth.divide(allClassTimes, CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP).doubleValue();
                    teacherClassGroupDto.setAvgClassTimesOfMonth(monthConsumeRate);
                }

            }

//            ClassGroup classGroup = classGorupIdMap.get(teacherClassGroupDto.getClassGroupId().intValue());
//            teacherClassGroupDto.setSurplusClassTimes(classGroup.getTotalClassTimes() - classGroup.getCurrentClassTimes());
            Long aLong = currentClassTimes.get(teacherClassGroupDto.getClassGroupId().intValue());
            teacherClassGroupDto.setSurplusClassTimes(aLong == null ? 0 : aLong.intValue());
            Long classGroupNoStartClassTimes = noStartClassTimes.get(teacherClassGroupDto.getClassGroupId().intValue());
            classGroupNoStartClassTimes = classGroupNoStartClassTimes == null ? 0 : classGroupNoStartClassTimes;
            Long studentNum = classGroupStudentNumMap.get(teacherClassGroupDto.getClassGroupId().intValue());
            teacherClassGroupDto.setStudentNum(Objects.isNull(studentNum) ? 0 : studentNum.intValue());

            String subjectIdList = teacherClassGroupDto.getSubjectIdList();
            if (StringUtils.isNotEmpty(subjectIdList)) {
                if (Objects.nonNull(musicGroupIdAndNum) && Objects.nonNull(musicGroupIdAndNum.get(teacherClassGroupDto.getMusicGroupId()))) {
                    teacherClassGroupDto.setThreeClassNoAttendanceStudentNum(musicGroupIdAndNum.get(teacherClassGroupDto.getMusicGroupId()));
                }
                String[] subjectIds = subjectIdList.split(",");
                List<String> subjectNameList = new ArrayList<>();
                for (String subjectId : subjectIds) {
                    subjectNameList.add(subjectMapBySubjectIdsList.get(Integer.parseInt(subjectId)));
                }
                teacherClassGroupDto.setSubjectNames(StringUtils.join(subjectNameList, ","));
            }
            //剩余课程为显示陪练报告入口rul
            if (teacherClassGroupDto.getType() == ClassGroupTypeEnum.PRACTICE) {
                List<CourseScheduleEvaluate> courseScheduleEvaluates = courseScheduleEvaluateDao.findByClassGroupIds(classGroupIds);
                Map<Integer, List<CourseScheduleEvaluate>> reportMap = new HashMap<>();
                if (courseScheduleEvaluates.size() > 0) {
                    reportMap = courseScheduleEvaluates.stream().collect(Collectors.groupingBy(CourseScheduleEvaluate::getClassGroupId));
                }
                if (reportMap.containsKey(teacherClassGroupDto.getClassGroupId().intValue())) {
                    List<CourseScheduleEvaluate> evaluates = reportMap.get(teacherClassGroupDto.getClassGroupId().intValue());
                    CourseScheduleEvaluate courseScheduleEvaluate = evaluates.get(evaluates.size() - 1);
                    teacherClassGroupDto.setHasReport(true);
                    String studyReportUrl = sysConfigDao.findConfigValue(SysConfigService.STUDENT_STUDY_REPORT_URL);
                    if (courseScheduleEvaluate.getVersion().equals(2)) {
                        String teacherBaseUrl = sysConfigDao.findConfigValue(SysConfigService.TEACHER_BASE_URL);
                        teacherClassGroupDto.setStudyReportUrl(teacherBaseUrl + "/#/studyReportNew?id=" + courseScheduleEvaluate.getId() + "&classGroupId=" + courseScheduleEvaluate.getClassGroupId());
                    } else {
                        teacherClassGroupDto.setStudyReportUrl(studyReportUrl + teacherClassGroupDto.getClassGroupId());
                    }
                } else if (teacherClassGroupDto.getBuyMonths() == null && classGroupNoStartClassTimes.intValue() == 0 && classGroupTeacherMap.get(teacherClassGroupDto.getClassGroupId().intValue()).equals(user.getId())) {
                    String studyReportUrl = sysConfigDao.findConfigValue(SysConfigService.TEACHER_STUDY_REPORT_URL);
                    teacherClassGroupDto.setStudyReportUrl(studyReportUrl + teacherClassGroupDto.getClassGroupId());
                }
            }
        });

        return teacherMusicClassGroup;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean updateClassStudentNum(Integer classGroupId, Integer num) {
        ClassGroup classGroup = classGroupDao.lockClassGroup(classGroupId);
        if (Objects.isNull(classGroup)) {
            throw new BizException("班级不存在");
        }
        classGroup.setStudentNum(classGroup.getStudentNum() + num);
        classGroup.setUpdateTime(new Date());

        classGroupDao.update(classGroup);

        return true;
    }

    @Override
    public boolean updateClassStudentNum(Integer classGroupId) {
        ClassGroup classGroup = classGroupDao.lockClassGroup(classGroupId);
        if (Objects.isNull(classGroup)) {
            throw new BizException("班级不存在");
        }
        Integer num = classGroupStudentMapperDao.countClassGroupStudentNum(classGroupId);
        classGroup.setStudentNum(num);
        classGroup.setUpdateTime(new Date());

        classGroupDao.update(classGroup);

        return true;
    }

    @Override
    public TeacherClassHeadInfo findTeacherClassGroupInfo(Integer classGroupId) {
        if (Objects.isNull(classGroupId)) {
            throw new BizException("请指定班级");
        }

        ClassGroup classGroup = classGroupDao.get(classGroupId.intValue());

        if (Objects.isNull(classGroup)) {
            throw new BizException("未找到该班级");
        }

        String subjectNames = subjectDao.findNames(classGroup.getSubjectIdList());

        TeacherClassHeadInfo teacherClassHeadInfo = new TeacherClassHeadInfo();
        teacherClassHeadInfo.setStudentNum(classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId()));
        teacherClassHeadInfo.setCurrentClassTimes(courseScheduleDao.countCurrentTimes(classGroup.getId(), new Date()));
        teacherClassHeadInfo.setTotalClassTimes(courseScheduleDao.countClassGroupCourses(classGroup.getId()));
        if (subjectNames != null && !subjectNames.isEmpty()) {
            teacherClassHeadInfo.setSubjectNames(subjectNames);
        }
        ClassGroupTeacherMapper bishopTeacher = classGroupTeacherMapperDao.findByClassGroupAndRole(classGroupId, TeachTypeEnum.BISHOP);
        if (Objects.nonNull(bishopTeacher)) {
            teacherClassHeadInfo.setBishopTeacherId(bishopTeacher.getId());
            teacherClassHeadInfo.setBishopTeacher(bishopTeacher.getUserName());
        }

        String name = classGroupTeacherMapperDao.queryTeachingNames(classGroupId);
        teacherClassHeadInfo.setTeachingTeacher(name);

//        ClassGroupTeacherMapper teachingTeacher = classGroupTeacherMapperDao.findByClassGroupAndRole(classGroupId, TeachTypeEnum.TEACHING);
//        if (Objects.nonNull(teachingTeacher)) {
//            teacherClassHeadInfo.setTeachingTeacherId(teachingTeacher.getId());
//            teacherClassHeadInfo.setTeachingTeacher(teachingTeacher.getUserName());
//        }

        if (classGroup.getType() == ClassGroupTypeEnum.VIP) {
            String[] studentNums = classGroupStudentMapperDao.findStudentNumByClassGroupId(classGroupId);
            teacherClassHeadInfo.setStudentNames(StringUtils.join(studentNums, ","));
        }
        if (classGroup.getType() == ClassGroupTypeEnum.PRACTICE) {
            String[] studentNums = classGroupStudentMapperDao.findStudentNumByClassGroupId(classGroupId);
            teacherClassHeadInfo.setStudentNames(StringUtils.join(studentNums, ","));
        }
        if (classGroup.getType() == ClassGroupTypeEnum.COMM) {
            String[] studentNums = classGroupStudentMapperDao.findStudentNumByClassGroupId(classGroupId);
            teacherClassHeadInfo.setStudentNames(StringUtils.join(studentNums, ","));
        }
        return teacherClassHeadInfo;
    }

    @Override
    public PageInfo findTeacherClassStudents(CourseScheduleQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List dataList = null;
        int count = classGroupStudentMapperDao.findClassStudentNum(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupStudentMapperDao.findClassStudent(params);
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public List<StudentAttendanceViewDto> findAttendanceStudentByCourse(Long courseScheduleId) {
        if (Objects.isNull(courseScheduleId)) {
            throw new BizException("请指定课程编号");
        }
        List<StudentAttendanceViewDto> studentByCourse = classGroupStudentMapperDao.findStudentByCourse(courseScheduleId);
        List<StudentAttendanceViewDto> leaveStudent = studentByCourse.stream()
                .filter(studentAttendanceViewDto -> StudentAttendanceStatusEnum.LEAVE.equals(studentAttendanceViewDto.getStatus()))
                .collect(Collectors.toList());
        List<StudentAttendanceViewDto> truantStudent = studentByCourse.stream()
                .filter(studentAttendanceViewDto -> StudentAttendanceStatusEnum.TRUANT.equals(studentAttendanceViewDto.getStatus()))
                .collect(Collectors.toList());
        List<StudentAttendanceViewDto> otherStudent = studentByCourse.stream()
                .filter(studentAttendanceViewDto -> !StudentAttendanceStatusEnum.LEAVE.equals(studentAttendanceViewDto.getStatus())
                        && !StudentAttendanceStatusEnum.TRUANT.equals(studentAttendanceViewDto.getStatus()))
                .collect(Collectors.toList());
        truantStudent.addAll(otherStudent);
        truantStudent.addAll(leaveStudent);
        if (!CollectionUtils.isEmpty(truantStudent)) {
            CourseSchedule schedule = courseScheduleDao.get(courseScheduleId);
            if (schedule.getGroupType() == MUSIC) {
                Set<Long> collect = truantStudent.stream().map(e -> e.getStudentId()).collect(Collectors.toSet());
                Map<Integer, String> paymentStatusMap = MapUtil.convertIntegerMap(musicGroupPaymentCalenderDao.queryUserCoursePaymentStatus(collect, schedule.getMusicGroupId()));
                truantStudent.forEach(studentAttendanceViewDto -> {
                    studentAttendanceViewDto.setPaymentStatus(paymentStatusMap.get(studentAttendanceViewDto.getStudentId().intValue()));
                });
            }
            List<StudentAttendanceViewDto> tempIds = truantStudent.stream()
                    .filter(studentAttendanceViewDto -> studentAttendanceViewDto.getGroupType().equals("MUSIC"))
                    .collect(Collectors.toList());

            if (!CollectionUtils.isEmpty(tempIds)&&schedule.getGroupType() == MUSIC) {
                List<Map<Integer, String>> studentSubjectNameMaps = subjectDao.findStudentSubjectNameMaps(tempIds);
                Map<Integer, String> studentSubjectNameMap = MapUtil.convertIntegerMap(studentSubjectNameMaps);
                List<Map<Integer, Long>> studentSubjectIdMaps = subjectDao.findStudentSubjectIdMaps(tempIds);
                Map<Integer, Long> studentSubjectIdMap = MapUtil.convertIntegerMap(studentSubjectIdMaps);
                truantStudent.forEach(studentAttendanceViewDto -> {
                    studentAttendanceViewDto.setSubjectName(studentSubjectNameMap.get(studentAttendanceViewDto.getStudentId().intValue()));
                    studentAttendanceViewDto.setSubjectId(studentSubjectIdMap.get(studentAttendanceViewDto.getStudentId().intValue()));
                });
            }else if(schedule.getGroupType() != MUSIC){
                ClassGroup classGroup = classGroupDao.get(schedule.getClassGroupId());
                Subject subject = subjectDao.get(Integer.valueOf(classGroup.getSubjectIdList()));
                truantStudent.forEach(studentAttendanceViewDto -> {
                    studentAttendanceViewDto.setSubjectName(subject.getName());
                    studentAttendanceViewDto.setSubjectId(Objects.nonNull(subject.getId())?subject.getId().longValue():0);
                });
            }
        }
        return truantStudent;
    }

    @Override
    public PageInfo findAttendanceStudentByCourseWithPage(CourseScheduleQueryInfo queryInfo) {
        PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<StudentAttendanceViewDto> dataList = null;
        int count = classGroupStudentMapperDao.countStudentByCourseWithPage(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupStudentMapperDao.findStudentByCourseWithPage(params);
            List<StudentAttendanceViewDto> tempIds = dataList.stream()
                    .filter(studentAttendanceViewDto -> studentAttendanceViewDto.getGroupType().equals("MUSIC"))
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(tempIds)) {
                List<Map<Integer, String>> studentSubjectNameMaps = subjectDao.findStudentSubjectNameMaps(tempIds);
                Map<Integer, String> studentSubjectNameMap = MapUtil.convertIntegerMap(studentSubjectNameMaps);
                dataList.forEach(studentAttendanceViewDto -> {
                    studentAttendanceViewDto.setSubjectName(studentSubjectNameMap.get(studentAttendanceViewDto.getStudentId().intValue()));
                });
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup classGroupAdjust(List<ClassGroup4MixDto> classGroup4MixDtos) {
        Date date = new Date();
        String musicGroupId = classGroup4MixDtos.get(0).getMusicGroupId();
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }
        if (classGroup4MixDtos.get(0).getCourseTimes().compareTo(0) <= 0) {
            throw new BizException("排课次数必须大于0");
        }

        Integer schoolId = musicGroup.getSchoolId();

        List<Integer> studentIdList = classGroup4MixDtos.get(0).getStudents();
        List<StudentRegistration> studentList = studentRegistrationService.findStudentListByUserIdList(musicGroupId, studentIdList);


        List<Integer> subjectIdList = studentList.stream().map(student -> student.getActualSubjectId()).collect(Collectors.toList());
        TeachModeEnum teachMode = TeachModeEnum.OFFLINE;
        if (classGroup4MixDtos.get(0).getType().equals(ClassGroupTypeEnum.HIGH_ONLINE)) {
            subjectIdList.clear();
            subjectIdList.add(classGroup4MixDtos.get(0).getSubjectId());
            teachMode = TeachModeEnum.ONLINE;
        }

        List<Subject> subjectList = subjectService.findBySubjectByIdList(subjectIdList);

        String subjectIds = subjectList.stream().map(subject -> subject.getId().toString()).collect(Collectors.joining(","));
        String subjectNames = subjectList.stream().map(subject -> subject.getName()).collect(Collectors.joining("/"));

        if (classGroup4MixDtos.get(0).getType().equals(ClassGroupTypeEnum.MUSIC_NETWORK)) {
            teachMode = TeachModeEnum.ONLINE;
            List<String> studentNames = studentDao.getStudentNames(studentIdList);
            classGroup4MixDtos.get(0).setClassGroupName(subjectNames + "•" + StringUtils.join(studentNames, ","));
        }

        if (classGroup4MixDtos.get(0).getType() == null) {
            classGroup4MixDtos.get(0).setType(ClassGroupTypeEnum.NORMAL);
        }
        //1、新建班级
        ClassGroup classGroup = new ClassGroup();
        classGroup.setMusicGroupId(classGroup4MixDtos.get(0).getMusicGroupId());
        classGroup.setSubjectIdList(subjectIds);
        classGroup.setName(classGroup4MixDtos.get(0).getClassGroupName());
        classGroup.setExpectStudentNum(studentList.size());
        classGroup.setStudentNum(studentList.size());
        classGroup.setType(classGroup4MixDtos.get(0).getType());
        classGroup.setDelFlag(0);
        classGroup.setGroupType(MUSIC);
        classGroup.setCurrentClassTimes(0);
        classGroup.setTotalClassTimes(classGroup4MixDtos.get(0).getCourseTimes());
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        classGroupDao.insert(classGroup);


        //2、将学生加入新班级（学生注册表，关联表
        List<ClassGroupStudentMapper> classGroupStudentMapperList = new ArrayList<>();
        List<Integer> userIds = new ArrayList<>(); //用户ids
        for (StudentRegistration studentRegistration : studentList) {
            if (classGroup4MixDtos.get(0).getType().equals(ClassGroupTypeEnum.NORMAL)) {
                studentRegistration.setClassGroupId(classGroup.getId());
                studentRegistrationService.update(studentRegistration);
            }

            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setMusicGroupId(musicGroupId);
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapper.setUserId(studentRegistration.getUserId());
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(MUSIC);
            classGroupStudentMapperList.add(classGroupStudentMapper);

            userIds.add(studentRegistration.getUserId());
        }
        classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentMapperList);


        //3、将老师加入关联关系
        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroup4MixDtos.get(0).getClassGroupTeacherMapperList();

        Set<Integer> noRepeatTeacherIds = classGroupTeacherMapperList.stream().map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toSet());
        if (noRepeatTeacherIds.size() != classGroupTeacherMapperList.size()) {
            throw new BizException("主教与助教存在冲突");
        }

        List<Integer> teacherIds = new ArrayList<>();
        Integer teacherId = null;
        for (ClassGroupTeacherMapper groupTeacherMapper : classGroupTeacherMapperList) {
            groupTeacherMapper.setGroupType(classGroup.getGroupType());
            groupTeacherMapper.setClassGroupId(classGroup.getId());
            groupTeacherMapper.setMusicGroupId(classGroup4MixDtos.get(0).getMusicGroupId());
            teacherIds.add(groupTeacherMapper.getUserId());
            if (groupTeacherMapper.getTeacherRole().equals(TeachTypeEnum.BISHOP)) {
                teacherId = groupTeacherMapper.getUserId();
            }
        }
        classGroupTeacherMapperDao.classGroupTeachersInsert(classGroupTeacherMapperList);

        List<Integer> allTeacherIds = classGroupTeacherMapperList.stream()
                .map(ClassGroupTeacherMapper::getUserId)
                .collect(Collectors.toList());

        //所有教师列表
        List<Teacher> teachers = teacherDao.findByTeacherIds(allTeacherIds);
        Map<Integer, Teacher> teacherMap = teachers.stream()
                .collect(Collectors.toMap(Teacher::getId, teacher -> teacher));

        //创建IM群组
        addImGroup(classGroup, userIds, teacherIds);


        Map<String, Integer> courseTypeMinutesMap = musicGroupPaymentCalenderCourseSettingsService.getMusicCourseSettingsWithStudents(musicGroupId, studentIdList);

        //计算每节课的课酬
        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = new ArrayList<>();
        List<CourseSchedule> courseScheduleList = new ArrayList<>();

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        for (ClassGroup4MixDto classGroup4MixDto : classGroup4MixDtos) {
            if (classGroup4MixDto.getCourseTimeDtoList() == null || classGroup4MixDto.getCourseTimeDtoList().size() == 0) {
                break;
            }
            //5、插入班级排课信息
            LocalDateTime now = LocalDate.parse(classGroup4MixDto.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();

            long totalCourseDuration = 0;

            if (!courseTypeMinutesMap.containsKey(classGroup4MixDto.getCourseType().getCode())) {
                throw new BizException("{}课程类型暂无剩余课程时长", classGroup4MixDto.getCourseType().getMsg());
            }
            Integer totalMinutes = courseTypeMinutesMap.get(classGroup4MixDto.getCourseType().getCode());
//            classGroup4MixDto.setCourseTimes(totalMinutes/(int)courseDuration);

            if (classGroup4MixDto.getCourseTimes() <= 0) {
                throw new BizException("{}课程类型剩余课程时长不足", classGroup4MixDto.getCourseType().getMsg());
            }

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

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

            WhileNode:
            while (true) {
                if (classGroup4MixDto.getHoliday() && holidayDays.contains(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))) {
                    now = now.plusDays(1);
                    continue;
                }
                int dayOfWeek = now.getDayOfWeek().getValue();//当前星期
                for (CourseTimeDto courseTimeDto : classGroup4MixDto.getCourseTimeDtoList()) {
                    if (courseTimeDto.getDayOfWeek() < 1 || courseTimeDto.getDayOfWeek() > 7) {
                        throw new BizException("排课循环周期错误，请核查");
                    }
                    if (!courseTimeDto.getDayOfWeek().equals(dayOfWeek)) continue;

                    //课时长度
                    long classCourseDuration = Duration.between(LocalDateTime.parse(classGroup4MixDto.getStartDate() + " " + courseTimeDto.getStartClassTime() + ":00", formatter),
                            LocalDateTime.parse(classGroup4MixDto.getStartDate() + " " + courseTimeDto.getEndClassTime() + ":00", formatter))
                            .toMinutes();

                    totalCourseDuration += classCourseDuration;

                    if (totalCourseDuration > totalMinutes) {
                        break WhileNode;
                    }

                    Date classDate = DateConvertor.toDate(now);
                    String startClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getStartClassTime() + ":00";
                    String endClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getEndClassTime() + ":00";

                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setSchoolId(schoolId);
                    courseSchedule.setMusicGroupId(musicGroupId);
                    courseSchedule.setClassGroupId(classGroup.getId());
                    courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                    courseSchedule.setClassDate(classDate);
                    courseSchedule.setStartClassTime(DateUtil.stringToDate(startClassTime));
                    courseSchedule.setEndClassTime(DateUtil.stringToDate(endClassTime));
                    courseSchedule.setCreateTime(date);
                    courseSchedule.setUpdateTime(date);
                    courseSchedule.setTeachMode(teachMode);
                    courseSchedule.setType(classGroup4MixDto.getCourseType());
                    courseSchedule.setGroupType(MUSIC);
                    courseSchedule.setOrganId(musicGroup.getOrganId());
                    if (classGroup4MixDto.getCourseType().equals(CourseSchedule.CourseScheduleType.MIX)) {
                        courseSchedule.setName(classGroup4MixDto.getCourseType().getMsg());
                    } else if (classGroup4MixDto.getCourseType().equals(CourseScheduleType.MUSIC_NETWORK)) {
                        courseSchedule.setName(classGroup.getName());
                    } else {
                        courseSchedule.setName(subjectNames + "-" + classGroup4MixDto.getCourseType().getMsg());
                    }
                    courseSchedule.setTeacherId(teacherId);
                    courseSchedule.setActualTeacherId(teacherId);
                    courseScheduleDao.insert(courseSchedule);
                    courseScheduleList.add(courseSchedule);

                    for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {

                        CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                        courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
                        courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
                        courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
                        courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
                        courseScheduleTeacherSalary.setUserId(classGroupTeacherMapper.getUserId());
                        courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
                        courseScheduleTeacherSalary.setMusicGroupId(musicGroupId);
                        courseScheduleTeacherSalary.setCreateTime(date);
                        courseScheduleTeacherSalary.setUpdateTime(date);
                        courseScheduleTeacherSalaryService.createMusicGroupCourseTeacherSalary(musicGroup, courseSchedule, courseScheduleTeacherSalary);
                        courseScheduleTeacherSalaryList.add(courseScheduleTeacherSalary);
                    }
                }
                now = now.plusDays(1);
            }
        }

        if (courseScheduleList.size() > 0) {
            //检测新排课冲突
            courseScheduleService.checkNewCourseSchedules(courseScheduleList, false, false);
        }

        //老师结算表
        if (courseScheduleTeacherSalaryList.size() > 0) {
            courseScheduleTeacherSalaryService.batchInsert(courseScheduleTeacherSalaryList);
        }
        //学生结算表
        if (courseScheduleList.size() > 0) {
            courseScheduleStudentPaymentService.createForMusicGroup(musicGroupId, courseScheduleList, studentIdList);
            studentDao.updateStudentServiceTag(null, studentIdList, YesOrNoEnum.YES.getCode());
        }
        return classGroup;
    }

    @Transactional(rollbackFor = Exception.class)
    public List<CourseSchedule> getCourseSchedules(ClassGroup4MixDto classGroup4MixDto, List<CourseSchedule> courseScheduleList, MusicGroupStudentClassAdjust classAdjust) {
        Date date = new Date();
        String musicGroupId = classGroup4MixDto.getMusicGroupId();
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        Integer schoolId = musicGroup.getSchoolId();

        TeachModeEnum teachMode = TeachModeEnum.OFFLINE;
        if (classGroup4MixDto.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE)) {
            teachMode = TeachModeEnum.ONLINE;
        } else if (classGroup4MixDto.getType().equals(ClassGroupTypeEnum.MUSIC_NETWORK)) {
            teachMode = TeachModeEnum.ONLINE;
        }

        if (classGroup4MixDto.getType() == null) {
            classGroup4MixDto.setType(ClassGroupTypeEnum.NORMAL);
        }

        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroup4MixDto.getClassGroupTeacherMapperList();

        Integer teacherId = null;
        for (ClassGroupTeacherMapper groupTeacherMapper : classGroupTeacherMapperList) {
            if (groupTeacherMapper.getTeacherRole().equals(TeachTypeEnum.BISHOP)) {
                teacherId = groupTeacherMapper.getUserId();
            }
        }

        String classCourseMinute = classGroup4MixDto.getClassCourseMinute();
        LocalDateTime now = LocalDate.parse(classGroup4MixDto.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
        //获取默认的排课时长
        JSONObject jsonObject = JSON.parseObject(classAdjust.getDefaultCourseTypeMinute());

//        String courseDefaultMinutes = sysConfigDao.findConfigValue("music_course_default_minutes");
//        JSONObject jsonObject = JSON.parseObject(courseDefaultMinutes);
        long classCourseDuration = Integer.parseInt(jsonObject.get(classGroup4MixDto.getCourseType().getCode()).toString());
//
        Map<String, Integer> classCourseMinuteMap = JSON.parseObject(classCourseMinute, Map.class);
        classGroup4MixDto.setCourseTimes(classCourseMinuteMap.get(classGroup4MixDto.getCourseType().getCode()) / (int) classCourseDuration);

        List<Integer> studentIdList = classGroup4MixDto.getStudents();
        List<StudentRegistration> studentList = studentRegistrationService.findStudentListByUserIdList(musicGroupId, studentIdList);

        List<Integer> subjectIdList = studentList.stream().map(student -> student.getActualSubjectId()).collect(Collectors.toList());
        List<Subject> subjectList = subjectService.findBySubjectByIdList(subjectIdList);

        String subjectNames = subjectList.stream().map(subject -> subject.getName()).collect(Collectors.joining("/"));

        Set<String> holidayDays = new HashSet<>();
        if (classGroup4MixDto.getHoliday()) {
            SysConfig holidaySetting = sysConfigService.findByParamName(SysConfigService.HOLIDAY_SETTING);
            if (Objects.nonNull(holidaySetting) && StringUtils.isNotBlank(holidaySetting.getParanValue())) {
                holidayDays = new HashSet<>(JSON.parseArray(holidaySetting.getParanValue(), String.class));
            }
        }
        ClassGroup classGroup = classGroup4MixDto.getClassGroup();
        courseScheduleList.clear();
        int times = 0;
        WhileNode:
        while (true) {
            if (classGroup4MixDto.getHoliday() && holidayDays.contains(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))) {
                now = now.plusDays(1);
                continue;
            }
            int dayOfWeek = now.getDayOfWeek().getValue();//当前星期
            for (CourseTimeDto courseTimeDto : classGroup4MixDto.getCourseTimeDtoList()) {
                if (courseTimeDto.getDayOfWeek() < 1 || courseTimeDto.getDayOfWeek() > 7) {
                    throw new BizException("排课循环周期错误，请核查");
                }
                if (!courseTimeDto.getDayOfWeek().equals(dayOfWeek)) continue;
                Date classDate = DateConvertor.toDate(now);
                String startClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getStartClassTime() + ":00";
                String endClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getEndClassTime() + ":00";

                CourseSchedule courseSchedule = new CourseSchedule();
                courseSchedule.setSchoolId(schoolId);
                courseSchedule.setMusicGroupId(musicGroupId);
                courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                courseSchedule.setClassDate(classDate);
                courseSchedule.setStartClassTime(DateUtil.stringToDate(startClassTime));
                courseSchedule.setEndClassTime(DateUtil.stringToDate(endClassTime));
                courseSchedule.setCreateTime(date);
                courseSchedule.setUpdateTime(date);
                courseSchedule.setTeachMode(teachMode);
                courseSchedule.setType(classGroup4MixDto.getCourseType());
                courseSchedule.setGroupType(MUSIC);
                courseSchedule.setOrganId(musicGroup.getOrganId());
                courseSchedule.setTeacherId(teacherId);
                courseSchedule.setActualTeacherId(teacherId);
                courseSchedule.setClassGroupId(classGroup.getId());
                if (classGroup4MixDto.getCourseType().equals(CourseSchedule.CourseScheduleType.MIX)) {
                    courseSchedule.setName(classGroup4MixDto.getCourseType().getMsg());
                } else if (classGroup4MixDto.getCourseType().equals(CourseScheduleType.MUSIC_NETWORK)) {
                    courseSchedule.setName(classGroup.getName());
                } else {
                    courseSchedule.setName(subjectNames + "-" + classGroup4MixDto.getCourseType().getMsg());
                }
                courseScheduleList.add(courseSchedule);

                times++;

                if (classGroup4MixDto.getCourseTimes().equals(times)) {
                    break WhileNode;
                }
            }
            now = now.plusDays(1);
        }
        return courseScheduleList;
    }

    @Transactional(rollbackFor = Exception.class)
    public ClassGroup createClassGroup(ClassGroup4MixDto classGroup4MixDto) {
        Date date = new Date();
        String musicGroupId = classGroup4MixDto.getMusicGroupId();
        List<Integer> studentIdList = classGroup4MixDto.getStudents();
        List<StudentRegistration> studentList = studentRegistrationService.findStudentListByUserIdList(musicGroupId, studentIdList);

        List<Integer> subjectIdList = studentList.stream().map(student -> student.getActualSubjectId()).collect(Collectors.toList());
        if (classGroup4MixDto.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE)) {
            subjectIdList.clear();
            subjectIdList.add(classGroup4MixDto.getSubjectId());
        }

        List<Subject> subjectList = subjectService.findBySubjectByIdList(subjectIdList);
        String subjectIds = subjectList.stream().map(subject -> subject.getId().toString()).collect(Collectors.joining(","));
        //1、新建班级
        ClassGroup classGroup = new ClassGroup();
        classGroup.setMusicGroupId(classGroup4MixDto.getMusicGroupId());
        classGroup.setSubjectIdList(subjectIds);
        classGroup.setName(classGroup4MixDto.getClassGroupName());
        classGroup.setExpectStudentNum(studentList.size());
        classGroup.setStudentNum(studentList.size());
        classGroup.setType(classGroup4MixDto.getType());
        classGroup.setDelFlag(0);
        classGroup.setGroupType(MUSIC);
        classGroup.setCurrentClassTimes(0);
        classGroup.setTotalClassTimes(classGroup4MixDto.getCourseTimes());
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        classGroupDao.insert(classGroup);
        return classGroup;
    }

    @Transactional(rollbackFor = Exception.class)
    public List<CourseSchedule> autoAdjust(ClassGroup4MixDto classGroup4MixDto, List<CourseSchedule> courseScheduleList, MusicGroupStudentClassAdjust classAdjust) {
        Boolean checkFlag = courseScheduleService.checkNewCourseSchedules(courseScheduleList, false, true);
        if (!checkFlag) {
            //排课开始时间加一周
            Date stringToDate = DateUtil.stringToDate(classGroup4MixDto.getStartDate(), DateUtil.ISO_EXPANDED_DATE_FORMAT);
            classGroup4MixDto.setStartDate(DateUtil.format(DateUtil.addDays(stringToDate, 7), DateUtil.ISO_EXPANDED_DATE_FORMAT));
            //再次尝试排课
            courseScheduleList = getCourseSchedules(classGroup4MixDto, courseScheduleList, classAdjust);
            autoAdjust(classGroup4MixDto, courseScheduleList, classAdjust);
        }
        return courseScheduleList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup classGroupAdjust2(ClassGroup4MixDto classGroup4MixDto) {
        Date date = new Date();
        String musicGroupId = classGroup4MixDto.getMusicGroupId();
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }
        if (classGroup4MixDto.getCourseTimes().compareTo(0) <= 0) {
            throw new BizException("排课次数必须大于0");
        }

        List<Integer> studentIdList = classGroup4MixDto.getStudents();
        List<StudentRegistration> studentList = studentRegistrationService.findStudentListByUserIdList(musicGroupId, studentIdList);

        if (classGroup4MixDto.getType() == null) {
            classGroup4MixDto.setType(ClassGroupTypeEnum.NORMAL);
        }

        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroup4MixDto.getClassGroupTeacherMapperList();

        MusicGroupStudentClassAdjust classAdjust = musicGroupStudentClassAdjustDao.get(classGroup4MixDto.getMusicGroupStudentClassAdjustId());
        ClassGroup classGroup = classGroup4MixDto.getClassGroup();
        if (classGroup == null) {
            //建班
            classGroup = createClassGroup(classGroup4MixDto);
            classGroup4MixDto.setClassGroup(classGroup);
            //2、将学生加入新班级（学生注册表，关联表
            List<ClassGroupStudentMapper> classGroupStudentMapperList = new ArrayList<>();
            List<Integer> userIds = new ArrayList<>(); //用户ids
            for (StudentRegistration studentRegistration : studentList) {
                if (classGroup4MixDto.getType().equals(ClassGroupTypeEnum.NORMAL)) {
                    studentRegistration.setClassGroupId(classGroup.getId());
                    studentRegistrationService.update(studentRegistration);
                }

                ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
                classGroupStudentMapper.setMusicGroupId(musicGroupId);
                classGroupStudentMapper.setClassGroupId(classGroup.getId());
                classGroupStudentMapper.setUserId(studentRegistration.getUserId());
                classGroupStudentMapper.setCreateTime(date);
                classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
                classGroupStudentMapper.setGroupType(MUSIC);
                classGroupStudentMapperList.add(classGroupStudentMapper);

                userIds.add(studentRegistration.getUserId());
            }
            classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentMapperList);

            List<Integer> teacherIds = new ArrayList<>();
            for (ClassGroupTeacherMapper groupTeacherMapper : classGroupTeacherMapperList) {
                groupTeacherMapper.setGroupType(classGroup.getGroupType());
                groupTeacherMapper.setClassGroupId(classGroup.getId());
                groupTeacherMapper.setMusicGroupId(classGroup4MixDto.getMusicGroupId());
                teacherIds.add(groupTeacherMapper.getUserId());
            }
            //3、将老师加入关联关系
            classGroupTeacherMapperDao.classGroupTeachersInsert(classGroupTeacherMapperList);
            //创建IM群组
            addImGroup(classGroup, userIds, teacherIds);
        }
        //排课
        List<CourseSchedule> courseScheduleList = new ArrayList<>();
        getCourseSchedules(classGroup4MixDto, courseScheduleList, classAdjust);

        //自动排课，校验冲突
        if (courseScheduleList.size() > 0) {
            //冲突校验
            courseScheduleList = autoAdjust(classGroup4MixDto, courseScheduleList, classAdjust);

            courseScheduleDao.batchAddCourseSchedules(courseScheduleList);

            //计算每节课的课酬
            List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = new ArrayList<>();

            for (CourseSchedule courseSchedule : courseScheduleList) {
                //默认课程时长
                for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
                    CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                    courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
                    courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
                    courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
                    courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
                    courseScheduleTeacherSalary.setUserId(classGroupTeacherMapper.getUserId());
                    courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
                    courseScheduleTeacherSalary.setMusicGroupId(musicGroupId);
                    courseScheduleTeacherSalary.setCreateTime(date);
                    courseScheduleTeacherSalary.setUpdateTime(date);
                    courseScheduleTeacherSalaryService.createMusicGroupCourseTeacherSalary(musicGroup, courseSchedule, courseScheduleTeacherSalary);
                    courseScheduleTeacherSalaryList.add(courseScheduleTeacherSalary);
                }
            }

            //老师结算表
            if (courseScheduleTeacherSalaryList.size() > 0) {
                courseScheduleTeacherSalaryService.batchInsert(courseScheduleTeacherSalaryList);
            }
            Integer musicGroupStudentClassAdjustId = classGroup4MixDto.getMusicGroupStudentClassAdjustId();
            //学生结算表
            courseScheduleStudentPaymentService.createForMusicGroup(courseScheduleList, studentIdList, musicGroupStudentClassAdjustId);
            return classGroup;
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup classGroupUpdate(List<ClassGroup4MixDto> classGroup4MixDtos) {
        Date date = new Date();
        Integer classGroupId = classGroup4MixDtos.get(0).getClassGroupId();
        String musicGroupId = classGroup4MixDtos.get(0).getMusicGroupId();
        ClassGroup classGroup = classGroupDao.get(classGroupId);
        if (classGroup == null) {
            throw new BizException("班级不存在");
        }

        TeachModeEnum teachMode = TeachModeEnum.OFFLINE;
        if (classGroup.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE) || classGroup.getType().equals(ClassGroupTypeEnum.MUSIC_NETWORK)) {
            teachMode = TeachModeEnum.ONLINE;
        }

        List<ClassGroupTeacherMapper> byClassGroup = classGroupTeacherMapperDao.findByClassGroup(classGroupId);
        List<ClassGroupTeacherMapper> newTeacherMapperList = classGroup4MixDtos.get(0).getClassGroupTeacherMapperList();
        MusicGroup musicGroup = musicGroupDao.get(classGroup.getMusicGroupId());
        if(musicGroup.getStatus() == PROGRESS){
            if (byClassGroup != null && byClassGroup.size() > 0) {
                ClassGroupTeacherMapper groupTeacherMapper = byClassGroup.stream().filter(classGroupTeacherMapper -> classGroupTeacherMapper.getTeacherRole() == TeachTypeEnum.BISHOP).findFirst().get();
                if (groupTeacherMapper != null) {
                    imGroupMemberService.quit(classGroupId.longValue(), groupTeacherMapper.getUserId());
                }
            }
            if (newTeacherMapperList.size() > 0) {
                //获取之前的班级老师
                Set<Integer> groupTeacher = classGroupDao.findGroupTeacher(classGroupId);
                groupTeacher.forEach(e -> {
                    imGroupMemberService.quit(classGroupId.longValue(), e);
                });
                newTeacherMapperList.forEach(e -> {
                    imGroupMemberService.join(classGroupId.longValue(), e.getUserId(), "指导老师", false);
                });
            }
        }
        if (Objects.nonNull(classGroup4MixDtos.get(0).getCourseAddType()) && classGroup4MixDtos.get(0).getCourseAddType().equals("onlyUpdateTeacher")) {
            List<Integer> classGroupIds = new ArrayList<>();
            classGroupIds.add(classGroupId);
            // 删除历史记录
            classGroupTeacherMapperDao.delClassGroupTeacherMapper(classGroupIds);
            for (ClassGroupTeacherMapper tm : newTeacherMapperList) {
                tm.setClassGroupId(classGroupId);
                tm.setCreateTime(date);
                tm.setGroupType(GroupType.MUSIC);
                tm.setMusicGroupId(musicGroupId);
                tm.setUpdateTime(date);
                classGroupTeacherMapperDao.insert(tm);
            }
            return classGroup;
        }
        if (classGroup4MixDtos.get(0).getCourseTimes().compareTo(0) <= 0) {
            throw new BizException("排课次数必须大于0");
        }
        Integer courseTimes = classGroup4MixDtos.get(0).getCourseTimes();

        classGroupService.updateTotalClassTimes(classGroup.getId(), courseTimes);

        Integer schoolId = teachMode.equals(TeachModeEnum.ONLINE) ? null : musicGroup.getSchoolId();

        List<Subject> subjectList = subjectService.findBySubjectByIdList(classGroup.getSubjectIdList());

        String subjectNames = subjectList.stream().map(Subject::getName).collect(Collectors.joining("/"));

        //1、更新班级关联老师信息
        List<ClassGroupTeacherMapper> newClassGroupTeacherMapperList = classGroup4MixDtos.get(0).getClassGroupTeacherMapperList();

        Set<Integer> noRepeatTeacherIds = newClassGroupTeacherMapperList.stream().map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toSet());
        if (noRepeatTeacherIds.size() != newClassGroupTeacherMapperList.size()) {
            throw new BizException("主教与助教存在冲突");
        }

        Integer teacherId = null;
        for (ClassGroupTeacherMapper groupTeacherMapper : newClassGroupTeacherMapperList) {
            groupTeacherMapper.setGroupType(classGroup.getGroupType());
            groupTeacherMapper.setClassGroupId(classGroup.getId());
            groupTeacherMapper.setMusicGroupId(classGroup4MixDtos.get(0).getMusicGroupId());
            if (groupTeacherMapper.getTeacherRole().equals(TeachTypeEnum.BISHOP)) {
                teacherId = groupTeacherMapper.getUserId();
            }
        }

        List<Integer> allTeacherIds = newClassGroupTeacherMapperList.stream()
                .map(ClassGroupTeacherMapper::getUserId)
                .collect(Collectors.toList());

        Set<String> newTeacher = newClassGroupTeacherMapperList.stream().map(
                classGroupTeacherMapper -> classGroupTeacherMapper.getTeacherRole().getCode() + classGroupTeacherMapper.getUserId()
        ).collect(Collectors.toSet());

        List<ClassGroupTeacherMapper> oldClassGroupTeacherMapperList = classGroupTeacherMapperDao.findClassGroupTeachers(classGroup.getId().toString());

        Set<String> oldTeacher = oldClassGroupTeacherMapperList.stream().map(
                classGroupTeacherMapper -> classGroupTeacherMapper.getTeacherRole().getCode() + classGroupTeacherMapper.getUserId()
        ).collect(Collectors.toSet());

        if (oldTeacher.size() != newTeacher.size() || !newTeacher.containsAll(oldTeacher)) {
            classGroupTeacherMapperService.classGroupTeachersInsert(newClassGroupTeacherMapperList);
        }

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        //2、获取班级学生
        List<StudentRegistration> studentList = classGroupStudentMapperDao.findClassStudentList(classGroup.getId(), ClassGroupStudentStatusEnum.NORMAL);

        List<Integer> studentIds = studentList.stream().map(StudentRegistration::getUserId).collect(Collectors.toList());

        Map<String, Integer> courseTypeMinutesMap = musicGroupPaymentCalenderCourseSettingsService.getMusicCourseSettingsWithStudents(musicGroupId, studentIds);

        //计算每节课的课酬
        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = new ArrayList<>();
        List<CourseSchedule> courseScheduleList = new ArrayList<>();

        for (ClassGroup4MixDto classGroup4MixDto : classGroup4MixDtos) {
            //3、插入班级排课信息
            LocalDateTime now = LocalDate.parse(classGroup4MixDto.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();

            if (!courseTypeMinutesMap.containsKey(classGroup4MixDto.getCourseType().getCode())) {
                throw new BizException("{}课程类型暂无剩余课程时长", classGroup4MixDto.getCourseType().getMsg());
            }
            Integer totalMinutes = courseTypeMinutesMap.get(classGroup4MixDto.getCourseType().getCode());
            long totalCourseDuration = 0;

            if (classGroup4MixDto.getCourseTimes() <= 0) {
                throw new BizException("{}课程类型剩余课程时长不足", classGroup4MixDto.getCourseType().getMsg());
            }

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

            WhileNode:
            while (true) {
                if (classGroup4MixDto.getHoliday() && holidayDays.contains(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))) {
                    now = now.plusDays(1);
                    continue;
                }
                int dayOfWeek = now.getDayOfWeek().getValue();
                for (CourseTimeDto courseTimeDto : classGroup4MixDto.getCourseTimeDtoList()) {
                    if (courseTimeDto.getDayOfWeek() < 1 || courseTimeDto.getDayOfWeek() > 7) {
                        throw new BizException("排课循环周期错误，请核查");
                    }
                    if (!courseTimeDto.getDayOfWeek().equals(dayOfWeek)) continue;

                    //课时长度
                    long classCourseDuration = Duration.between(LocalDateTime.parse(classGroup4MixDto.getStartDate() + " " + courseTimeDto.getStartClassTime() + ":00", formatter),
                            LocalDateTime.parse(classGroup4MixDto.getStartDate() + " " + courseTimeDto.getEndClassTime() + ":00", formatter))
                            .toMinutes();

                    totalCourseDuration += classCourseDuration;

                    if (totalCourseDuration > totalMinutes) {
                        break WhileNode;
                    }

                    Date classDate = DateConvertor.toDate(now);
                    String startClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getStartClassTime() + ":00";
                    String endClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getEndClassTime() + ":00";

                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setSchoolId(schoolId);
                    courseSchedule.setClassGroupId(classGroup.getId());
                    courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                    courseSchedule.setClassDate(classDate);
                    courseSchedule.setStartClassTime(DateUtil.stringToDate(startClassTime));
                    courseSchedule.setEndClassTime(DateUtil.stringToDate(endClassTime));
                    courseSchedule.setCreateTime(date);
                    courseSchedule.setUpdateTime(date);
                    courseSchedule.setTeachMode(teachMode);
                    courseSchedule.setMusicGroupId(classGroup.getMusicGroupId());
                    courseSchedule.setType(classGroup4MixDto.getCourseType());
                    if (!StringUtils.isBlank(classGroup.getName())) {
                        courseSchedule.setName(classGroup.getName());
                    } else {
                        courseSchedule.setName(subjectNames + "-" + classGroup4MixDto.getCourseType().getMsg());
                    }
                    courseSchedule.setGroupType(MUSIC);
                    courseSchedule.setTeacherId(teacherId);
                    courseSchedule.setActualTeacherId(teacherId);
                    courseSchedule.setOrganId(musicGroup.getOrganId());
                    courseSchedule.setClassGroupType(classGroup.getType().getCode());
                    courseScheduleDao.insert(courseSchedule);
                    courseScheduleList.add(courseSchedule);

                    for (ClassGroupTeacherMapper classGroupTeacherMapper : newClassGroupTeacherMapperList) {
                        CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                        courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
                        courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
                        courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
                        courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
                        courseScheduleTeacherSalary.setUserId(classGroupTeacherMapper.getUserId());
                        courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
                        courseScheduleTeacherSalary.setCreateTime(date);
                        courseScheduleTeacherSalary.setUpdateTime(date);
                        courseScheduleTeacherSalaryService.createMusicGroupCourseTeacherSalary(musicGroup, courseSchedule, courseScheduleTeacherSalary);
                        courseScheduleTeacherSalaryList.add(courseScheduleTeacherSalary);
                    }
                }

                now = now.plusDays(1);
            }
        }

        courseScheduleService.checkNewCourseSchedules(courseScheduleList, false, false);

        //老师结算表
        if (courseScheduleTeacherSalaryList.size() > 0) {
            courseScheduleTeacherSalaryService.batchInsert(courseScheduleTeacherSalaryList);
        }

        if (!CollectionUtils.isEmpty(studentList)) {
            studentDao.updateStudentServiceTag(null, studentIds, YesOrNoEnum.YES.getCode());

            //学生结算表
            courseScheduleStudentPaymentService.createForMusicGroup(musicGroupId, courseScheduleList, studentIds);
        }
        if(musicGroup.getStatus() == PROGRESS){
            imUserFriendService.refreshClassImUserFriend(classGroupId);
        }
        return classGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ClassGroup classGroupSnap(List<ClassGroup4MixDto> classGroup4MixDtos) throws Exception {
        Date date = new Date();
        String musicGroupId = classGroup4MixDtos.get(0).getMusicGroupId();
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }
        if (classGroup4MixDtos.get(0).getCourseTimes().compareTo(0) <= 0) {
            throw new BizException("排课次数必须大于0");
        }
        Integer schoolId = musicGroup.getSchoolId();

        List<Integer> studentIdList = classGroup4MixDtos.get(0).getStudents();

        List<StudentRegistration> studentList = studentRegistrationService.findStudentListByUserIdList(musicGroupId, studentIdList);

        List<Integer> subjectIdList = studentList.stream().map(studentRegistration -> studentRegistration.getActualSubjectId()).collect(Collectors.toList());

        List<Subject> subjectList = subjectService.findBySubjectByIdList(subjectIdList);

        String subjectIds = subjectList.stream().map(subject -> subject.getId().toString()).collect(Collectors.joining(","));
        String subjectNames = subjectList.stream().map(subject -> subject.getName()).collect(Collectors.joining("/"));

        //1、新建班级
        ClassGroup classGroup = new ClassGroup();
        classGroup.setMusicGroupId(classGroup4MixDtos.get(0).getMusicGroupId());
        classGroup.setSubjectIdList(subjectIds);
        classGroup.setName(classGroup4MixDtos.get(0).getClassGroupName());
        classGroup.setExpectStudentNum(studentList.size());
        classGroup.setStudentNum(studentList.size());
        classGroup.setType(ClassGroupTypeEnum.SNAP);
        classGroup.setGroupType(MUSIC);
        classGroup.setDelFlag(0);
        classGroup.setTotalClassTimes(classGroup4MixDtos.get(0).getCourseTimes());
        classGroup.setCurrentClassTimes(0);
        classGroup.setCreateTime(date);
        classGroup.setUpdateTime(date);
        classGroupDao.insert(classGroup);


        //2、将学生加入新班级，关联表
        List<Integer> userIds = new ArrayList<>();
        List<ClassGroupStudentMapper> classGroupStudentMapperList = new ArrayList<>();
        for (StudentRegistration studentRegistration : studentList) {
            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setMusicGroupId(musicGroupId);
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapper.setUserId(studentRegistration.getUserId());
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(MUSIC);
            classGroupStudentMapperList.add(classGroupStudentMapper);
            userIds.add(studentRegistration.getUserId());
        }
        classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentMapperList);

        //3、将老师加入关联关系
        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroup4MixDtos.get(0).getClassGroupTeacherMapperList();

        Set<Integer> noRepeatTeacherIds = classGroupTeacherMapperList.stream().map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toSet());
        if (noRepeatTeacherIds.size() != classGroupTeacherMapperList.size()) {
            throw new BizException("主教与助教存在冲突");
        }

        Integer teacherId = null;
        List<Integer> teacherIds = new ArrayList<>();
        for (ClassGroupTeacherMapper groupTeacherMapper : classGroupTeacherMapperList) {
            groupTeacherMapper.setGroupType(classGroup.getGroupType());
            groupTeacherMapper.setClassGroupId(classGroup.getId());
            groupTeacherMapper.setMusicGroupId(classGroup4MixDtos.get(0).getMusicGroupId());
            teacherIds.add(groupTeacherMapper.getUserId());
            if (groupTeacherMapper.getTeacherRole().equals(TeachTypeEnum.BISHOP)) {
                teacherId = groupTeacherMapper.getUserId();
            }
        }
        classGroupTeacherMapperDao.classGroupTeachersInsert(classGroupTeacherMapperList);

        List<Integer> allTeacherIds = classGroupTeacherMapperList.stream()
                .map(ClassGroupTeacherMapper::getUserId)
                .collect(Collectors.toList());

        //所有教师列表
        List<Teacher> teachers = teacherDao.findByTeacherIds(allTeacherIds);
        Map<Integer, Teacher> teacherMap = teachers.stream()
                .collect(Collectors.toMap(Teacher::getId, teacher -> teacher));

        //创建IM群组
        addImGroup(classGroup, userIds, teacherIds);

        Map<String, Integer> courseTypeMinutesMap = musicGroupPaymentCalenderCourseSettingsService.getMusicCourseSettingsWithStudents(musicGroupId, studentIdList);

        //计算每节课的课酬
        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaryList = new ArrayList<>();
        List<CourseSchedule> courseScheduleList = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        for (ClassGroup4MixDto classGroup4MixDto : classGroup4MixDtos) {
            //5、插入班级排课信息
            LocalDateTime now = LocalDate.parse(classGroup4MixDto.getStartDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();

            if (!courseTypeMinutesMap.containsKey(classGroup4MixDto.getCourseType().getCode())) {
                throw new BizException("{}课程类型暂无剩余课程时长", classGroup4MixDto.getCourseType().getMsg());
            }
            Integer totalMinutes = courseTypeMinutesMap.get(classGroup4MixDto.getCourseType().getCode());
            long totalCourseDuration = 0;
//            classGroup4MixDto.setCourseTimes(totalMinutes/(int)courseDuration);

            if (classGroup4MixDto.getCourseTimes() <= 0) {
                throw new BizException("{}课程类型剩余课程时长不足", classGroup4MixDto.getCourseType().getMsg());
            }

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

            WhileNode:
            while (true) {
                if (classGroup4MixDto.getHoliday() && holidayDays.contains(now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))) {
                    now = now.plusDays(1);
                    continue;
                }

                int dayOfWeek = now.getDayOfWeek().getValue();
                for (CourseTimeDto courseTimeDto : classGroup4MixDto.getCourseTimeDtoList()) {
                    if (courseTimeDto.getDayOfWeek() < 1 || courseTimeDto.getDayOfWeek() > 7) {
                        throw new BizException("排课循环周期错误，请核查");
                    }
                    if (!courseTimeDto.getDayOfWeek().equals(dayOfWeek)) continue;

                    //课时长度
                    long classCourseDuration = Duration.between(LocalDateTime.parse(classGroup4MixDto.getStartDate() + " " + courseTimeDto.getStartClassTime() + ":00", formatter),
                            LocalDateTime.parse(classGroup4MixDto.getStartDate() + " " + courseTimeDto.getEndClassTime() + ":00", formatter))
                            .toMinutes();

                    totalCourseDuration += classCourseDuration;

                    if (totalCourseDuration > totalMinutes) {
                        break WhileNode;
                    }

                    Date classDate = DateConvertor.toDate(now);
                    String startClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getStartClassTime() + ":00";
                    String endClassTime = DateUtil.getDate(classDate) + " " + courseTimeDto.getEndClassTime() + ":00";

                    CourseSchedule courseSchedule = new CourseSchedule();
                    courseSchedule.setSchoolId(schoolId);
                    courseSchedule.setMusicGroupId(musicGroupId);
                    courseSchedule.setClassGroupId(classGroup.getId());
                    courseSchedule.setStatus(CourseStatusEnum.NOT_START);
                    courseSchedule.setClassDate(classDate);
                    courseSchedule.setStartClassTime(DateUtil.stringToDate(startClassTime));
                    courseSchedule.setEndClassTime(DateUtil.stringToDate(endClassTime));
                    courseSchedule.setCreateTime(date);
                    courseSchedule.setUpdateTime(date);
                    courseSchedule.setTeachMode(TeachModeEnum.OFFLINE);
                    courseSchedule.setType(classGroup4MixDto.getCourseType());
                    courseSchedule.setGroupType(MUSIC);
                    courseSchedule.setMusicGroupId(classGroup.getMusicGroupId());
                    if (classGroup4MixDto.getCourseType().equals(CourseSchedule.CourseScheduleType.MIX)) {
                        courseSchedule.setName(classGroup4MixDto.getCourseType().getMsg());
                    } else {
                        courseSchedule.setName(subjectNames + "-" + classGroup4MixDto.getCourseType().getMsg());
                    }
                    courseSchedule.setTeacherId(teacherId);
                    courseSchedule.setActualTeacherId(teacherId);
                    courseSchedule.setOrganId(musicGroup.getOrganId());
                    courseScheduleList.add(courseSchedule);

                    courseScheduleDao.insert(courseSchedule);

                    for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
                        CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                        courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
                        courseScheduleTeacherSalary.setMusicGroupId(musicGroupId);
                        courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
                        courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
                        courseScheduleTeacherSalary.setTeacherRole(classGroupTeacherMapper.getTeacherRole());
                        courseScheduleTeacherSalary.setUserId(classGroupTeacherMapper.getUserId());
                        courseScheduleTeacherSalary.setClassGroupId(classGroup.getId());
                        courseScheduleTeacherSalary.setCreateTime(date);
                        courseScheduleTeacherSalary.setUpdateTime(date);
                        courseScheduleTeacherSalaryService.createMusicGroupCourseTeacherSalary(musicGroup, courseSchedule, courseScheduleTeacherSalary);
                        courseScheduleTeacherSalaryList.add(courseScheduleTeacherSalary);
                    }
                }

                now = now.plusDays(1);
            }
        }

//        courseScheduleService.checkSnapCourseShchedules(courseScheduleList);

        courseScheduleService.checkNewCourseSchedules(courseScheduleList, false, false);

        //老师结算表
        if (courseScheduleTeacherSalaryList.size() > 0) {
            courseScheduleTeacherSalaryService.batchInsert(courseScheduleTeacherSalaryList);
        }

        //学生结算表
        if (!CollectionUtils.isEmpty(studentIdList)) {
            courseScheduleStudentPaymentService.createForMusicGroup(musicGroupId, courseScheduleList, studentIdList);
            studentDao.updateStudentServiceTag(null, studentIdList, YesOrNoEnum.YES.getCode());
        }
        return classGroup;
    }

    @Override
    public PageInfo<MusicGroupClassGroupDto> queryMusicGroupClassGroup(QueryInfo queryInfo) {
        PageInfo<MusicGroupClassGroupDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<MusicGroupClassGroupDto> dataList = null;
        int count = classGroupDao.countMusicGroupClassGroup(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupDao.queryMusicGroupClassGroup(params);
            List<Integer> classGroups = dataList.stream().map(e -> e.getClassGroupId()).collect(Collectors.toList());
            Map<Integer, Long> totalNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalNumByClassGroupId(classGroups, null));
            Map<Integer, Long> currentNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countExpendNumByClassGroupId(classGroups));
            String join = StringUtils.join(classGroups, ",");
            //获取主教老师
            Map<Integer, String> masterTeachers = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(classGroupDao.countStudentNum(join, "BISHOP"))), HashMap.class);
            //获取助教老师
            Map<Integer, String> subTeachers = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(classGroupDao.countStudentNum(join, "TEACHING"))), HashMap.class);
            //获取在读人数
            Map<Integer, Integer> studyNums = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(classGroupDao.countStudyNum(join))), HashMap.class);
            //获取退班人数
            Map<Integer, Integer> quitNums = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(classGroupDao.countQuitNum(join))), HashMap.class);
            dataList.forEach(e -> {
                Long aLong = totalNumMap.get(e.getClassGroupId());
                e.setTotalClassTimes(aLong == null ? 0 : aLong.intValue());
                Long aLong1 = currentNumMap.get(e.getClassGroupId());
                e.setCurrentClassTimes(aLong1 == null ? 0 : aLong1.intValue());
                e.setMasterTeacher(masterTeachers.get(e.getClassGroupId()));
                e.setSubTeacher(subTeachers.get(e.getClassGroupId()));
                e.setStudyNum(studyNums.get(e.getClassGroupId()));
                e.setQuitNum(quitNums.get(e.getClassGroupId()));
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public PageInfo<MusicGroupCourseScheduleDto> queryMusicGroupCourseSchedule(queryMusicGroupCourseScheduleQueryInfo queryInfo) {
        PageInfo<MusicGroupCourseScheduleDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<MusicGroupCourseScheduleDto> dataList = null;
        int count = classGroupDao.countMusicGroupCourseSchedule(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupDao.queryMusicGroupCourseSchedule(params);
            //所有课程编号的列表
            List<Integer> couseScheduleIds = dataList.stream().map(MusicGroupCourseScheduleDto::getCourseScheduleId).distinct().collect(Collectors.toList());

            //主教老师
            List<CourseScheduleTeacherSalary> bishopTeachers = courseScheduleTeacherSalaryDao.findByCourseScheduleIdsAndTeacherRole(couseScheduleIds, "BISHOP");
            Map<Long, List<CourseScheduleTeacherSalary>> courseScheduleBishopTeacherMaps = bishopTeachers.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));

            //助教老师
            List<CourseScheduleTeacherSalary> teachingTeachers = courseScheduleTeacherSalaryDao.findByCourseScheduleIdsAndTeacherRole(couseScheduleIds, "TEACHING");
            Map<Long, List<CourseScheduleTeacherSalary>> courseScheduleTeachingTeacherMaps = teachingTeachers.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));

            dataList.forEach(e -> {
                List<CourseScheduleTeacherSalary> currentBishopTeacher = courseScheduleBishopTeacherMaps.get(e.getCourseScheduleId().longValue());
                List<CourseScheduleTeacherSalary> TeachingTeachers = new ArrayList<>();
                if (!Objects.isNull(currentBishopTeacher) && !CollectionUtils.isEmpty(currentBishopTeacher)) {
                    e.setMasterTeacherId(currentBishopTeacher.get(0).getUserId());
                    e.setMasterTeacherName(currentBishopTeacher.get(0).getUserName());
                } else {
                    currentBishopTeacher = new ArrayList<>();
                }
                TeachingTeachers.addAll(currentBishopTeacher);
                List<CourseScheduleTeacherSalary> currentCourseTeachingTeachers = courseScheduleTeachingTeacherMaps.get(e.getCourseScheduleId().longValue());
                if (Objects.isNull(currentCourseTeachingTeachers) || CollectionUtils.isEmpty(currentCourseTeachingTeachers)) {
                    currentCourseTeachingTeachers = new ArrayList<>();
                }
                TeachingTeachers.addAll(currentCourseTeachingTeachers);
                e.setTeachingTeachers(TeachingTeachers);
                e.setTeacherNum(TeachingTeachers.size());
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public PageInfo<MusicGroupCourseScheduleDto> queryMusicGroupCourseScheduleDetail(queryMusicGroupCourseScheduleQueryInfo queryInfo) {
        PageInfo<MusicGroupCourseScheduleDto> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        List<MusicGroupCourseScheduleDto> dataList = null;
        int count = classGroupDao.countMusicGroupCourseScheduleDetail(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupDao.queryMusicGroupCourseScheduleDetail(params);
            //获取当前合奏班班级编号列表
//            Set<Integer> mixClassGroupIds = dataList.stream().map(e -> e.getMixClassGroupId()).collect(Collectors.toSet());
//            String mixClassGroupIdsStr = StringUtils.join(mixClassGroupIds, ",");
            //所有课程编号的列表
            List<Integer> courseScheduleIds = dataList.stream().map(MusicGroupCourseScheduleDto::getCourseScheduleId).distinct().collect(Collectors.toList());
            //获取合奏班名称
//            Map<Integer, String> classGroupNames = MapUtil.convertMybatisMap(classGroupDao.findNameById(mixClassGroupIdsStr));

            //主教老师
            Map<Long, List<CourseScheduleTeacherSalary>> courseScheduleBishopTeacherMaps = new HashMap<>();

            //是否点名
            Map<Integer, Long> studentNumCourseMap = MapUtil.convertIntegerMap(studentAttendanceDao.countStudentAttendancesByCourses(courseScheduleIds));
            //助教老师
            Map<Long, List<CourseScheduleTeacherSalary>> courseScheduleTeachingTeacherMaps = new HashMap<>();
            if (!CollectionUtils.isEmpty(courseScheduleIds)) {
                List<CourseScheduleTeacherSalary> bishopTeachers = courseScheduleTeacherSalaryDao.findByCourseScheduleIdsAndTeacherRole(courseScheduleIds, "BISHOP");
                courseScheduleBishopTeacherMaps = bishopTeachers.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));

                //助教老师
                List<CourseScheduleTeacherSalary> teachingTeachers = courseScheduleTeacherSalaryDao.findByCourseScheduleIdsAndTeacherRole(courseScheduleIds, "TEACHING");
                courseScheduleTeachingTeacherMaps = teachingTeachers.stream().collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getCourseScheduleId));
            }
            MusicGroupCourseScheduleDto scheduleDto = null;
            for (int i = 0; i < dataList.size(); i++) {
                scheduleDto = dataList.get(i);
//                e.setMixClassGroupName(classGroupNames.get(e.getMixClassGroupId()));
                List<CourseScheduleTeacherSalary> currentBishopTeacher = courseScheduleBishopTeacherMaps.get(dataList.get(i).getCourseScheduleId().longValue());
                List<CourseScheduleTeacherSalary> TeachingTeachers = new ArrayList<>();
                if (!Objects.isNull(currentBishopTeacher) && !CollectionUtils.isEmpty(currentBishopTeacher)) {
                    dataList.get(i).setMasterTeacherId(currentBishopTeacher.get(0).getUserId());
                    dataList.get(i).setMasterTeacherName(currentBishopTeacher.get(0).getUserName());
                } else {
                    currentBishopTeacher = new ArrayList<>();
                }
                TeachingTeachers.addAll(currentBishopTeacher);
                List<CourseScheduleTeacherSalary> currentCourseTeachingTeachers = courseScheduleTeachingTeacherMaps.get(dataList.get(i).getCourseScheduleId().longValue());
                if (Objects.isNull(currentCourseTeachingTeachers) || CollectionUtils.isEmpty(currentCourseTeachingTeachers)) {
                    currentCourseTeachingTeachers = new ArrayList<>();
                }
                TeachingTeachers.addAll(currentCourseTeachingTeachers);
                dataList.get(i).setTeachingTeachers(TeachingTeachers);
                dataList.get(i).setTeacherNum(TeachingTeachers.size());
                Long studentNum = studentNumCourseMap.get(scheduleDto.getCourseScheduleId().longValue());
                if (Objects.nonNull(studentNum)) {
                    scheduleDto.setIsCallNames(studentNum > 0 ? YesOrNoEnum.YES : YesOrNoEnum.NO);
                } else {
                    scheduleDto.setIsCallNames(YesOrNoEnum.NO);
                }
                /*if (CollectionUtils.isEmpty(currentCourseTeachingTeachers) && !CollectionUtils.isEmpty(currentBishopTeacher)) {
                    currentCourseTeachingTeachers = new ArrayList<>();
                    if (currentBishopTeacher != null) {
                        currentCourseTeachingTeachers.add(currentBishopTeacher.get(0));
                    }
                    e.setTeacherNum(currentCourseTeachingTeachers.size());
                    e.setTeachingTeachers(currentCourseTeachingTeachers);
                } else {
                    if (currentBishopTeacher != null) {
                        currentCourseTeachingTeachers.add(currentBishopTeacher.get(0));
                    }
                    e.setTeachingTeachers(currentCourseTeachingTeachers);
                }*/
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public boolean batchIncreaseClassTimes(List<Integer> classGroupList) {
        classGroupDao.batchIncreaseClassTimes(classGroupList);
        return true;
    }

    @Override
    public List<ClassGroupTeachersDto> classGroupAndTeacher(Integer classGroupId) {
        List<ClassGroupTeachersDto> classGroups = classGroupDao.findClassGroupByMixClassGroupId(classGroupId);
        String classGroupIds = "";
        for (ClassGroupTeachersDto classGroupTeachersDto : classGroups) {
            classGroupIds += classGroupTeachersDto.getId() + ",";
        }
        classGroupIds = classGroupIds.substring(0, classGroupIds.length() - 1);

        List<ClassGroupTeacherMapper> classGroupTeachers = classGroupTeacherMapperDao.findClassGroupTeachers(classGroupIds);
        for (ClassGroupTeachersDto classGroup : classGroups) {
            List<ClassGroupTeacherMapper> classGroupTeacherMappers = new ArrayList<>();
            for (ClassGroupTeacherMapper classGroupTeacher : classGroupTeachers) {
                if (!classGroup.getId().equals(classGroupTeacher.getClassGroupId())) continue;
                classGroupTeacherMappers.add(classGroupTeacher);
            }
            classGroup.setClassGroupTeacherMapperList(classGroupTeacherMappers);
        }
        return classGroups;
    }

    @Override
    public List<HighClassGroupDto> findClassGroupByMusicGroupIdAndSubjectId(String musicGroupId, Integer subjectId) {
        List<HighClassGroupDto> highClassGroupList = classGroupDao.findClassGroupByMusicGroupIdAndSubjectId(musicGroupId, subjectId);
        for (HighClassGroupDto highClassGroup : highClassGroupList) {
            List<String> subjects = subjectService.findBySubIds(highClassGroup.getSubjectIdList());
            highClassGroup.setSubjectName(subjects.stream().collect(Collectors.joining(",")));

            ClassGroupTeacherMapper bishopTeacher = classGroupTeacherMapperDao.findByClassGroupAndRole(highClassGroup.getId(), TeachTypeEnum.BISHOP);
            highClassGroup.setTeacherName(bishopTeacher.getUserName());
            highClassGroup.setUserId(bishopTeacher.getUserId());
            CourseSchedule courseSchedule = courseScheduleDao.findOneCourseScheduleByClassGroupId(highClassGroup.getId());
            if (courseSchedule != null) {
                highClassGroup.setStartClassTime(DateUtil.format(courseSchedule.getStartClassTime(), "HH:mm"));
                highClassGroup.setEndClassTime(DateUtil.format(courseSchedule.getEndClassTime(), "HH:mm"));

                Calendar calendar = Calendar.getInstance();
                calendar.setTime(courseSchedule.getClassDate());
                Integer dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
                dayOfWeek = dayOfWeek.equals(0) ? 7 : dayOfWeek;
                highClassGroup.setDayOfWeek(dayOfWeek);
            }
        }
        return highClassGroupList;
    }

    @Override
    public int batchUpdateClassCourseTimes(List<Integer> classGroupIds) {
        List<Map<Integer, Integer>> classGroupCourseTimesMaps = courseScheduleDao.countClassGroupCourseTimes(classGroupIds);
        Map<Integer, Integer> classGroupCourseTimesMap = MapUtil.convertIntegerMap(classGroupCourseTimesMaps);
        return classGroupDao.batchUpdateClassGroupCourseTimes(classGroupCourseTimesMap);
    }


    @Transactional(rollbackFor = Exception.class)
    public void addStudentIntoClassGroup(String musicGroupId, Integer classGroupId, List<Integer> studentIds) {
        List<ClassGroupStudentMapper> classGroupStudentMappers = new ArrayList<>();
        for (Integer studentId : studentIds) {
            ClassGroupStudentMapper classGroupStudentMapper = new ClassGroupStudentMapper(musicGroupId, classGroupId, studentId, ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(GroupType.VIP);
            classGroupStudentMappers.add(classGroupStudentMapper);
        }
        classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentMappers);
    }

    @Override
    public List<ClassGroupTeachersDto> getClassGroupAndTeacherByType(String musicGroupId, ClassGroupTypeEnum type) {
        List<ClassGroupTeachersDto> classGroups = classGroupDao.findClassGroupByType(musicGroupId, type);
        if (classGroups.size() == 0) {
            return null;
        }
        String classGroupIds = classGroups.stream().map(classGroup -> classGroup.getId().toString()).collect(Collectors.joining(","));
        List<Integer> classGroupSet = classGroups.stream().map(classGroup -> classGroup.getId()).collect(Collectors.toList());

        List<ClassGroupTeacherMapper> classGroupTeachers = classGroupTeacherMapperDao.findClassGroupTeachers(classGroupIds);
        Map<Integer, Integer> studyNums = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(classGroupDao.countStudyNum(classGroupIds))), HashMap.class);

        Map<Integer, Long> totalNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalNumByClassGroupId(classGroupSet, null));
        Map<Integer, Long> currentNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countExpendNumByClassGroupId(classGroupSet));

        for (ClassGroupTeachersDto classGroup : classGroups) {
            List<ClassGroupTeacherMapper> classGroupTeacherMappers = new ArrayList<>();
            for (ClassGroupTeacherMapper classGroupTeacher : classGroupTeachers) {
                if (!classGroup.getId().equals(classGroupTeacher.getClassGroupId())) continue;
                classGroupTeacherMappers.add(classGroupTeacher);
            }
            classGroup.setClassGroupTeacherMapperList(classGroupTeacherMappers);
            classGroup.setStudentNum(studyNums.get(classGroup.getId()));
            int totalClassTimes = 0;
            int currentClassTimes = 0;
            if (totalNumMap.containsKey(classGroup.getId())) {
                totalClassTimes = totalNumMap.get(classGroup.getId()).intValue();
            }
            if (currentNumMap.containsKey(classGroup.getId())) {
                currentClassTimes = currentNumMap.get(classGroup.getId()).intValue();
            }
            classGroup.setTotalClassTimes(totalClassTimes);
            classGroup.setCurrentClassTimes(currentClassTimes);
        }
        return classGroups;
    }

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

        List<ClassGroupTeachersDto> dataList = null;
        int count = classGroupDao.countClassGroup(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = classGroupDao.queryClassGroupPage(params);
            String classGroupIds = dataList.stream().map(classGroup -> classGroup.getId().toString()).collect(Collectors.joining(","));
            List<Integer> classGroupSet = dataList.stream().map(classGroup -> classGroup.getId()).collect(Collectors.toList());

            List<ClassGroupTeacherMapper> classGroupTeachers = classGroupTeacherMapperDao.findClassGroupTeachers(classGroupIds);
            Map<Integer, Integer> studyNums = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(classGroupDao.countStudyNum(classGroupIds))), HashMap.class);

            Map<Integer, Long> totalNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalNumByClassGroupId(classGroupSet, null));
            Map<Integer, Long> currentNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countExpendNumByClassGroupId(classGroupSet));

            for (ClassGroupTeachersDto classGroup : dataList) {
                List<ClassGroupTeacherMapper> classGroupTeacherMappers = new ArrayList<>();
                for (ClassGroupTeacherMapper classGroupTeacher : classGroupTeachers) {
                    if (!classGroup.getId().equals(classGroupTeacher.getClassGroupId())) continue;
                    classGroupTeacherMappers.add(classGroupTeacher);
                }
                classGroup.setClassGroupTeacherMapperList(classGroupTeacherMappers);
                classGroup.setStudentNum(studyNums.get(classGroup.getId()));
                int totalClassTimes = 0;
                int currentClassTimes = 0;
                if (totalNumMap.containsKey(classGroup.getId())) {
                    totalClassTimes = totalNumMap.get(classGroup.getId()).intValue();
                }
                if (currentNumMap.containsKey(classGroup.getId())) {
                    currentClassTimes = currentNumMap.get(classGroup.getId()).intValue();
                }
                classGroup.setTotalClassTimes(totalClassTimes);
                classGroup.setCurrentClassTimes(currentClassTimes);
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public Boolean addImGroup(ClassGroup classGroup, List<Integer> userIds, List<Integer> teacherIdList) {
        MusicGroup musicGroup = musicGroupDao.get(classGroup.getMusicGroupId());

        Map<Integer,String> userRoleMap = new HashMap<Integer, String>();
        userRoleMap.put(musicGroup.getEducationalTeacherId(), "乐团主管");
        userRoleMap.put(musicGroup.getTeamTeacherId(), "运营主管");
        userRoleMap.put(musicGroup.getDirectorUserId(), "乐队指导");
        for (Integer userId : userIds) {
            if (userId == null) continue;
            
            userRoleMap.put(userId, "");
        }
        
        if(teacherIdList != null && teacherIdList.size() > 0){
        	for(Integer teacherId : teacherIdList){
        		userRoleMap.put(teacherId, "指导老师");
        	}
        }
        
        imGroupService.create(classGroup.getId().longValue(), null, classGroup.getName(), musicGroup.getName(), musicGroup.getName(), musicGroup.getName(), null, "MUSIC");
        imGroupMemberService.join(classGroup.getId().longValue(), userRoleMap);
        return true;
    }

    @Override
    public Boolean checkSetSalary(String musicGroupId) {
        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalary = courseScheduleTeacherSalaryDao.findCourseScheduleTeacherSalaryByMusicGroupId(musicGroupId, MUSIC);
        if (courseScheduleTeacherSalary != null && courseScheduleTeacherSalary.size() > 0) {
            return true;
        }
        return false;
    }

    public Boolean batchAddImGroup(List<ClassGroupImGroupDto> classGroupImGroupList) {

        MusicGroup musicGroup = musicGroupDao.get(classGroupImGroupList.get(0).getClassGroup().getMusicGroupId());

        List<ImGroupModel> imGroupModelList = new ArrayList<>();
        for (ClassGroupImGroupDto classGroupImGroupDto : classGroupImGroupList) {
            List<Integer> userIdList = new ArrayList<>();
            userIdList.add(musicGroup.getEducationalTeacherId());
            userIdList.add(musicGroup.getTeamTeacherId());
            userIdList.add(musicGroup.getOperatorUserId());
            userIdList.add(musicGroup.getDirectorUserId());
            if (classGroupImGroupDto.getUserIds() != null && classGroupImGroupDto.getUserIds().size() > 0) {
                userIdList.addAll(classGroupImGroupDto.getUserIds());
            }

            List<ImGroupMember> imGroupMemberList = new ArrayList<>();
            for (Integer userId : userIdList) {
                if (userId == null) continue;
                imGroupMemberList.add(new ImGroupMember(userId.toString()));
            }
            //创建IM群组
            ImGroupMember[] imGroupMembers = imGroupMemberList.toArray(new ImGroupMember[imGroupMemberList.size()]);
            ImGroupModel imGroupModel = new ImGroupModel(classGroupImGroupDto.getClassGroup().getId().toString(), imGroupMembers, classGroupImGroupDto.getClassGroup().getName());
            imGroupModelList.add(imGroupModel);
        }
        //imFeignService.groupBatchCreate(imGroupModelList);
        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean updateTotalClassTimes(Integer classGroupId, Integer num) {
        ClassGroup classGroup = classGroupDao.lockClassGroup(classGroupId);
        if (Objects.isNull(classGroup)) {
            throw new BizException("班级不存在");
        }
        int totalClassTimes = classGroup.getTotalClassTimes() == null ? 0 : classGroup.getTotalClassTimes();
        classGroup.setTotalClassTimes(totalClassTimes + num);
        classGroup.setUpdateTime(new Date());

        classGroupDao.update(classGroup);

        return true;
    }

    @Override
    public void updateClassGroupInfo(Integer classGroupId) {
        Date now = new Date();
        ClassGroup classGroup = classGroupDao.get(classGroupId);
        List<CourseSchedule> courseSchedules = courseScheduleDao.findClassGroupCourseSchedules(classGroupId);
        int totalClassTimes = courseSchedules.size();
        int currentClassTimes = 0;
        for (CourseSchedule courseSchedule : courseSchedules) {
            if (courseSchedule.getEndClassTime().before(now)) {
                currentClassTimes += 1;
            }
        }

        classGroup.setTotalClassTimes(totalClassTimes);
        classGroup.setCurrentClassTimes(currentClassTimes);
        Integer studentNum = classGroupStudentMapperDao.countClassGroupStudentNum(classGroupId);
        classGroup.setStudentNum(studentNum);
        if (classGroup.getGroupType().equals(GroupType.VIP)) {
            VipGroup vipGroup = vipGroupDao.get(Long.parseLong(classGroup.getMusicGroupId()));
            if (currentClassTimes < totalClassTimes
                    && vipGroup.getStatus().equals(VipGroupStatusEnum.FINISHED)) {
                vipGroup.setStatus(VipGroupStatusEnum.PROGRESS);
            }
            if (currentClassTimes >= totalClassTimes
                    && vipGroup.getStatus().equals(VipGroupStatusEnum.PROGRESS)
                    && Objects.nonNull(vipGroup.getCoursesExpireDate())
                    && vipGroup.getCoursesExpireDate().after(now)) {
                vipGroup.setStatus(VipGroupStatusEnum.FINISHED);
            }
            vipGroupDao.update(vipGroup);
        }
        classGroupDao.update(classGroup);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateClassGroupsCourseInfo(List<Integer> classGroupIds) {
        if (CollectionUtils.isEmpty(classGroupIds)) {
            return;
        }
        List<ClassGroup> classGroups = classGroupDao.findClassGroupWithIds(classGroupIds);
        if (CollectionUtils.isEmpty(classGroups)) {
            return;
        }
        Map<Integer, ClassGroup> idClassGroupMap = classGroups.stream().collect(Collectors.toMap(ClassGroup::getId, classGroup -> classGroup));
        List<CourseSchedule> classGroupsCourseSchedules = courseScheduleDao.findCourseSchedulesByClassGroups(classGroupIds);
        Map<Integer, List<CourseSchedule>> classGroupCourseMap = classGroupsCourseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getClassGroupId));
        Date now = new Date();
        for (Map.Entry<Integer, ClassGroup> classGroupEntry : idClassGroupMap.entrySet()) {
            List<CourseSchedule> courseSchedules = classGroupCourseMap.get(classGroupEntry.getKey());
            if (CollectionUtils.isEmpty(courseSchedules)) {
                classGroupEntry.getValue().setTotalClassTimes(0);
                classGroupEntry.getValue().setCurrentClassTimes(0);
                continue;
            }
            int totalClassTimes = courseSchedules.size();
            int currentClassTimes = 0;
            for (CourseSchedule courseSchedule : courseSchedules) {
                if (courseSchedule.getEndClassTime().before(now)) {
                    currentClassTimes += 1;
                }
            }
            classGroupEntry.getValue().setTotalClassTimes(totalClassTimes);
            classGroupEntry.getValue().setCurrentClassTimes(currentClassTimes);
        }
        classGroupDao.batchUpdate(classGroups);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delClassNoStartCourse(Integer classGroupId) {
        Date date = new Date();
        ClassGroup classGroup = classGroupDao.get(classGroupId);
        if (classGroup == null) {
            throw new BizException("班级不存在");
        }

        List<CourseSchedule> noStartCourses = courseScheduleService.findNoStartCoursesByClassGroupId(classGroup.getId());
        if (noStartCourses == null || noStartCourses.size() <= 0) {
            return true;
        }
        List<Long> courseScheduleIds = noStartCourses.stream().map(courseSchedule -> courseSchedule.getId()).collect(Collectors.toList());
        courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
        courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
        teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
        courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
        return true;
    }

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

        if (StringUtils.isNotBlank(queryInfo.getSearch())) {
            List<Group> groups = groupDao.searchGroups(params);
            if (!CollectionUtils.isEmpty(groups)) {
                params.put("groups", groups);
            }
            List<Integer> studentClassGroupIds = classGroupDao.findClassGroupIdsByStudent(queryInfo.getSearch());
            List<Integer> teacherClassGroupIds = classGroupDao.findClassGroupIdsByTeacher(queryInfo.getSearch());
            studentClassGroupIds.addAll(teacherClassGroupIds);
            if (!CollectionUtils.isEmpty(studentClassGroupIds)) {
                params.put("classGroupIds", studentClassGroupIds);
            }
        }

        List<SuperClassGroupDto> results = new ArrayList<>();
        int count = classGroupDao.superCountClassGroups(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            results = classGroupDao.superFindClassGroups(params);
            List<Integer> classGroupIds = new ArrayList<>();
            for (SuperClassGroupDto result : results) {
                classGroupIds.add(result.getId());
            }
            List<ClassGroupTeacherMapDto> classGroupTeacherMaps = classGroupTeacherMapperDao.findByClassGroupIds(classGroupIds);
            Map<Integer, Map<TeachTypeEnum, List<ClassGroupTeacherMapDto>>> classTeacherTypeMaps = classGroupTeacherMaps.stream()
                    .collect(Collectors.groupingBy(ClassGroupTeacherMapDto::getClassGroupId, Collectors.groupingBy(ClassGroupTeacherMapDto::getTeacherRole)));
            List<Group> groups = groupDao.findByClassGroupIds(classGroupIds);
            Map<String, Map<GroupType, List<Group>>> groupsGroupByGroup = groups.stream().collect(Collectors.groupingBy(Group::getId, Collectors.groupingBy(Group::getGroupType)));
            results.forEach(result -> {
                Map<GroupType, List<Group>> groupsTypeMap = groupsGroupByGroup.get(result.getMusicGroupId());
                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());
                    }
                }
                Map<TeachTypeEnum, List<ClassGroupTeacherMapDto>> teachTypeEnumListMap = classTeacherTypeMaps.get(result.getId());
                if (Objects.nonNull(teachTypeEnumListMap)) {
                    for (TeachTypeEnum teachType : teachTypeEnumListMap.keySet()) {
                        List<ClassGroupTeacherMapDto> classGroupTeachers = teachTypeEnumListMap.get(teachType);
                        if (!CollectionUtils.isEmpty(classGroupTeachers)) {
                            List<String> userNames = classGroupTeachers.stream().map(ClassGroupTeacherMapDto::getUserName).collect(Collectors.toList());
                            if (teachType.equals(TeachTypeEnum.BISHOP)) {
                                result.setBishopTeacherNames(StringUtils.join(userNames.toArray(), ","));
                            }
                            if (teachType.equals(TeachTypeEnum.TEACHING)) {
                                result.setTeachingTeacherNames(StringUtils.join(userNames.toArray(), ","));
                            }
                        }
                    }
                }
            });
        }
        pageInfo.setRows(results);
        return pageInfo;
    }

    @Override
    public Map<String, Object> getUserInfoWithUserId(Integer groupId, Integer userId) {
        MusicGroup musicGroup = musicGroupDao.findByClassId(groupId);
        SysUser user = teacherDao.getUser(userId);
        Map<String, Object> map = new HashMap<>(4);
        if (musicGroup != null) {
            if (musicGroup.getTeamTeacherId() != null && userId.equals(musicGroup.getTeamTeacherId())) {
                map.put("name", user.getRealName() + "(运营主管)");
            } else if (musicGroup.getEducationalTeacherId() != null && userId.equals(musicGroup.getEducationalTeacherId())) {
                map.put("name", user.getRealName() + "(教务老师)");
            } else if (musicGroup.getDirectorUserId() != null && userId.equals(musicGroup.getDirectorUserId())) {
                map.put("name", user.getRealName() + "(乐队指导)");
            } else if (courseScheduleTeacherSalaryDao.isTeacher(groupId, userId)) {
                map.put("name", user.getRealName() + "(指导老师)");
            } else {
                map.put("name", user.getUsername());
            }
        } else {
            if (courseScheduleTeacherSalaryDao.isTeacher(groupId, userId)) {
                map.put("name", user.getRealName() + "(指导老师)");
            } else {
                map.put("name", user.getUsername());
            }
        }
        map.put("userId", userId);
        if (StringUtils.isEmpty(user.getAvatar())) {
            map.put("avatar", "https://daya-online.oss-cn-beijing.aliyuncs.com/201912/RkoZBNq.jpeg");
        } else {
            map.put("avatar", user.getAvatar());
        }
        return map;
    }

    @Override
    public void updateGroupName(Integer groupId, String groupName) {
        classGroupDao.updateGroupName(groupId, groupName);
    }

    @Override
    public TeacherClassHeadInfo findTeacherClassGroupInfoByCourseId(Integer courseId) {
        CourseSchedule courseSchedule = courseScheduleDao.get(courseId.longValue());
        Integer classGroupId = courseSchedule.getClassGroupId();

        ClassGroup classGroup = classGroupDao.get(classGroupId);

        if (Objects.isNull(classGroup)) {
            throw new BizException("未找到该班级");
        }

        String subjectNames = subjectDao.findNames(classGroup.getSubjectIdList());

        TeacherClassHeadInfo teacherClassHeadInfo = new TeacherClassHeadInfo();
        teacherClassHeadInfo.setStudentNum(classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId()));
        teacherClassHeadInfo.setCurrentClassTimes(courseScheduleDao.countCurrentTimes(classGroup.getId(), new Date()));
        teacherClassHeadInfo.setTotalClassTimes(courseScheduleDao.countClassGroupCourses(classGroup.getId()));
        if (subjectNames != null && !subjectNames.isEmpty()) {
            teacherClassHeadInfo.setSubjectNames(subjectNames);
        }
        ClassGroupTeacherMapper bishopTeacher = classGroupTeacherMapperDao.findByClassGroupAndRole(classGroupId, TeachTypeEnum.BISHOP);
        if (Objects.nonNull(bishopTeacher)) {
            teacherClassHeadInfo.setBishopTeacherId(bishopTeacher.getId());
            teacherClassHeadInfo.setBishopTeacher(bishopTeacher.getUserName());
        }

        String name = classGroupTeacherMapperDao.queryTeachingNames(classGroupId);
        teacherClassHeadInfo.setTeachingTeacher(name);

        if (classGroup.getType() == ClassGroupTypeEnum.VIP) {
            String[] studentNums = classGroupStudentMapperDao.findCourseStudentName(courseId);
            teacherClassHeadInfo.setStudentNames(StringUtils.join(studentNums, ","));
        }
        if (classGroup.getType() == ClassGroupTypeEnum.PRACTICE) {
            String[] studentNums = classGroupStudentMapperDao.findCourseStudentName(courseId);
            teacherClassHeadInfo.setStudentNames(StringUtils.join(studentNums, ","));
        }
        if (classGroup.getType() == ClassGroupTypeEnum.COMM) {
            String[] studentNums = classGroupStudentMapperDao.findCourseStudentName(courseId);
            teacherClassHeadInfo.setStudentNames(StringUtils.join(studentNums, ","));
        }
        return teacherClassHeadInfo;
    }


    @Override
    public ClassGroup findGroupById(Integer groupId) {
        ClassGroup classGroup = classGroupDao.get(groupId);
        if (classGroup != null) {
            classGroup.setViewGroupName(classGroup.getName());
            classGroup.setName(StringUtils.isEmpty(classGroup.getGroupName()) ? classGroup.getName() : classGroup.getGroupName());
            if (classGroup.getGroupType() == MUSIC) {
                MusicGroup musicGroup = musicGroupDao.get(classGroup.getMusicGroupId());
                if (musicGroup != null) {
                    classGroup.setMusicGroupName(musicGroup.getName());
                }
            }
        }
        return classGroup;
    }

    @Override
    public List<RemainCourseTypeDurationDto> queryRemainCourseTypeDuration(String classGroupIdList) {
        return courseScheduleDao.queryRemainCourseTypeDuration(classGroupIdList);
    }

    @Override
    public Map<String, Integer> classGroupSubCourseNum(Integer classGroupId) {
        return MapUtil.convertIntegerMap(courseScheduleDao.querySubCourseNumMap(classGroupId));
    }

    public Map<String, Object> getDefaultPaymentCalender(List<Integer> classGroupIds) {
        if (classGroupIds == null || classGroupIds.size() == 0) {
            throw new BizException("参数校验失败");
        }
        Map<String, Object> result = new HashMap<>();
        Map<Integer, Map<String, MusicGroupOrganizationCourseSettingsDetail>> resultMap = new HashMap<>();
        //获取所选班级最大剩余课时
        Map<String, Long> map = MapUtil.convertIntegerMap(courseScheduleDao.findClassMaxCourseNumMap(classGroupIds));
        //获取分布默认的课程类型单价
        MusicGroup musicGroup = musicGroupDao.findByClassGroupId(classGroupIds.get(0));
        Map<String, BigDecimal> unitPriceMap = MapUtil.convertIntegerMap(organizationCourseUnitPriceSettingsDao.queryMapByOrganIdAndChargeTypeId(musicGroup.getChargeTypeId(), musicGroup.getOrganId()));
        Set<String> courseTypes = map.keySet();
        Set<String> groupType = new HashSet<>();
        for (Integer classGroupId : classGroupIds) {
            Map<String, MusicGroupOrganizationCourseSettingsDetail> courseMap = new HashMap<>();
            //获取当前班级剩余课次
            Map<String, Long> subCourseNumMap = MapUtil.convertIntegerMap(courseScheduleDao.querySubCourseNumMap(classGroupId));
            for (String courseType : courseTypes) {
                groupType.add(courseType);
                Long currentNum = subCourseNumMap.get(courseType);
                if (currentNum == null) {
                    currentNum = 0l;
                }
                Long maxNum = map.get(courseType);
                //如果当前课程类型不需要新增缴费项目
                if (currentNum >= maxNum) {
                    continue;
                }
                Long subNum = maxNum - currentNum;
                //生成缴费项目
                MusicGroupOrganizationCourseSettingsDetail settingsDetail = new MusicGroupOrganizationCourseSettingsDetail();
                BigDecimal unitPrice = unitPriceMap.get(courseType);
                if (unitPrice == null) {
                    throw new BizException("分部默认课程类型单价不存在，请设置");
                }
                settingsDetail.setCourseTotalNum(subNum.intValue());
                settingsDetail.setCourseType(CourseScheduleType.valueOf(courseType));
                settingsDetail.setUnitPrice(unitPrice);
                courseMap.put(courseType, settingsDetail);
            }
            resultMap.put(classGroupId, courseMap);
        }
        result.put("defaultPaymentCalender", resultMap);
        result.put("groupTypeSet", groupType);
        result.put("classMaxCourseNumMap", map);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResponseResult mergeClassSplitClassAffirm(MergeClassSplitClassAffirmDto mergeClassSplitClassAffirmDto) {
        List<Integer> classGroupIds = mergeClassSplitClassAffirmDto.getClassGroupIds();
        if (classGroupIds == null || classGroupIds.size() == 0) {
            throw new BizException("参数校验失败");
        }
        //班级信息
        List<ClassGroup4MixDto> classGroup4MixDtos = mergeClassSplitClassAffirmDto.getClassGroup4MixDtos();
        if (CollectionUtils.isEmpty(classGroup4MixDtos)) {
            throw new BizException("请填写班级信息");
        }
        List<Integer> studentIds = mergeClassSplitClassAffirmDto.getStudentIds();
        if (CollectionUtils.isEmpty(studentIds)) {
            throw new BizException("学员列表不可为空");
        }
        SysUser sysUser = sysUserFeignService.queryUserInfo();

        MusicGroup musicGroup = musicGroupDao.findByClassGroupId(classGroupIds.get(0));
        //生成缴费记录,同一个批次
        MusicGroupPaymentCalender.PaymentCalenderStatusEnum status = null;
        List<MusicGroupPaymentCalenderDto> paymentCalenderDtos = mergeClassSplitClassAffirmDto.getMusicGroupPaymentCalenderDtos();
        StringBuffer batchNos = new StringBuffer();
        if (paymentCalenderDtos != null && paymentCalenderDtos.size() > 0) {
            for (MusicGroupPaymentCalenderDto calenderDto : paymentCalenderDtos) {
                if (status == null || status != AUDITING) {
                    List<MusicGroupPaymentCalenderCourseSettings> musicGroupPaymentCalenderCourseSettingsList = calenderDto.getMusicGroupPaymentCalenderCourseSettingsList();
                    for (MusicGroupPaymentCalenderCourseSettings courseSettings : musicGroupPaymentCalenderCourseSettingsList) {
                        OrganizationCourseUnitPriceSettings defaultUnitPrice = organizationCourseUnitPriceSettingsDao.queryByOrganIdAndCourseTypeAndChargeType(
                                musicGroup.getOrganId(), courseSettings.getCourseType(), musicGroup.getChargeTypeId());
                        if (defaultUnitPrice == null) {
                            throw new BizException("请先设置分部课程类型单价");
                        }
                        if (defaultUnitPrice.getUnitPrice().multiply(new BigDecimal(courseSettings.getCourseTotalMinuties())).setScale(0, BigDecimal.ROUND_HALF_UP)
                                .compareTo(courseSettings.getCourseCurrentPrice()) != 0) {
                            status = AUDITING;
                            break;
                        }
                    }
                }
            }
            List<String> batchNoList = new ArrayList<>();
            //创建缴费项目,  多个缴费项目分成多个批次号
            for (MusicGroupPaymentCalenderDto calenderDto : paymentCalenderDtos) {
                if (batchNoList.size() > 0) {
                    calenderDto.setIgnoreBatchNoList(batchNoList);
                }
                calenderDto.setMergeClassFlag(true);
                musicGroupPaymentCalenderService.create(calenderDto);
                if (batchNos.length() > 0) {
                    batchNos.append(",");
                }
                batchNoList.add(calenderDto.getBatchNo());
                batchNos.append(calenderDto.getBatchNo());
            }
        }

        //记录申请信息
        MusicGroupStudentClassAdjust musicGroupStudentClassAdjust = new MusicGroupStudentClassAdjust();
        musicGroupStudentClassAdjust.setBatchNo(batchNos.toString());
        musicGroupStudentClassAdjust.setMusicGroupId(musicGroup.getId());
        musicGroupStudentClassAdjust.setOperatorId(sysUser.getId());
        musicGroupStudentClassAdjust.setNewClassGroupJson(JSON.toJSONString(classGroup4MixDtos));
        musicGroupStudentClassAdjust.setClassGroupIds(JSON.toJSONString(classGroupIds));
        musicGroupStudentClassAdjust.setStudentIds(JSON.toJSONString(studentIds));
        List<Map<Integer, String>> classGroupStudents = mergeClassSplitClassAffirmDto.getClassGroupStudents();
        if (classGroupStudents != null && classGroupStudents.size() > 0) {
            musicGroupStudentClassAdjust.setClassGroupStudents(JSON.toJSONString(mergeClassSplitClassAffirmDto.getClassGroupStudents()));
        }

        //获取需要冻结的课程
        List<Long> allLockCourseIds = courseScheduleDao.queryStudentNotStartByClassIdsAndStudentIds(classGroupIds, null);
        musicGroupStudentClassAdjust.setAllLockCourseIds(JSON.toJSONString(allLockCourseIds));
        //获取需要删除的学员关联的课程
        List<Long> courseIds = courseScheduleDao.queryStudentNotStartByClassIdsAndStudentIds(classGroupIds, studentIds);
        musicGroupStudentClassAdjust.setSubLockCourseIds(JSON.toJSONString(courseIds));
        List<Long> studentPaymentIds = courseScheduleStudentPaymentDao.queryStudentNotStartByClassIdsAndStudentIds(classGroupIds, studentIds);

        musicGroupStudentClassAdjust.setStudentPaymentIds(JSON.toJSONString(studentPaymentIds));
        //保存老师选择的课程时长
        musicGroupStudentClassAdjust.setDefaultCourseTypeMinute(JSON.toJSONString(mergeClassSplitClassAffirmDto.getClassCourseMinuteMap()));
        //计算新增班级的可排课时长，总课次*默认时长  (用学员剩余的课程时长加上购买的时长，可能导致同一班级学员时长不一致)
        musicGroupStudentClassAdjust.setClassCourseMinute(JSON.toJSONString(findClassCourseMinuteMap(classGroupIds, mergeClassSplitClassAffirmDto.getClassCourseMinuteMap())));
        musicGroupStudentClassAdjustDao.insert(musicGroupStudentClassAdjust);
        //如果需要审核，校验参数配置
        checkMergeClassSplitClassAffirmParam(mergeClassSplitClassAffirmDto);
        HttpResponseResult httpResponseResult = new HttpResponseResult();
        httpResponseResult.setStatus(true);
        httpResponseResult.setCode(200);
        //如果缴费项目不需要审核，那么生成班级以及课表
        if (status == null || status != AUDITING) {
            //每种课程类型单独进行排课
            ClassGroup classGroup = null;
            for (ClassGroup4MixDto classGroup4MixDto : classGroup4MixDtos) {
                classGroup4MixDto.setClassGroup(classGroup);
                classGroup4MixDto.setMusicGroupStudentClassAdjustId(musicGroupStudentClassAdjust.getId());
                classGroup4MixDto.setClassCourseMinute(musicGroupStudentClassAdjust.getClassCourseMinute());
                classGroup = classGroupService.classGroupAdjust2(classGroup4MixDto);
            }
            //排课完成后删除所选课程
            courseScheduleDao.deleteMusicGroupCourseSchedulesWithStudents(courseIds, studentIds);
            //删除班级关联的学员
            if (classGroupStudents != null && classGroupStudents.size() > 0) {
                for (Map<Integer, String> classGroupStudent : classGroupStudents) {
                    Set<Integer> integers = classGroupStudent.keySet();
                    for (Integer integer : integers) {
                        List<Integer> collect = Arrays.asList(classGroupStudent.get(integer).split(",")).stream().map(e -> Integer.parseInt(e)).collect(Collectors.toList());
                        //学员退出群聊
                        imGroupMemberService.quit(integer.longValue(),collect);
                        classGroupStudentMapperDao.deleteByClassGroupIdAndStudents(integer, classGroupStudent.get(integer));
                    }
                }
            }
            List<Long> delCourseIds = courseScheduleDao.findNoStudentCourseIds(courseIds);
            if (delCourseIds != null && delCourseIds.size() > 0) {
                //删除课程
                courseScheduleDao.deleteCourseSchedulesByClassGroupIds(delCourseIds);
                //删除教师考勤
                teacherAttendanceDao.batchDeleteByCourseSchedules(delCourseIds);
                //删除教师课酬
                courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(delCourseIds);
            }
            imUserFriendService.refreshGroupImUserFriend(musicGroup.getId(),MUSIC);
            httpResponseResult.setMsg("学员班级调整完成");
        } else {
            //冻结班级
            classGroupDao.batchUpdateLockByClassGroupIds(classGroupIds, 1);
            //冻结所选班级的课程
            courseScheduleDao.batchUpdateLockByCourseIds(allLockCourseIds, 1);
            httpResponseResult.setMsg("学员班级调整申请已提交,缴费项目审核中");
        }
        return httpResponseResult;
    }

    public void checkMergeClassSplitClassAffirmParam(MergeClassSplitClassAffirmDto mergeClassSplitClassAffirmDto) {
        ClassGroup4MixDto classGroup4MixDto = mergeClassSplitClassAffirmDto.getClassGroup4MixDtos().get(0);
        if (classGroup4MixDto.getCourseTimes().compareTo(0) <= 0) {
            throw new BizException("排课次数必须大于0");
        }
        List<ClassGroupTeacherMapper> classGroupTeacherMapperList = classGroup4MixDto.getClassGroupTeacherMapperList();
        if (classGroupTeacherMapperList == null || classGroupTeacherMapperList.size() == 0) {
            throw new BizException("请设置上课老师");
        }
        Set<Integer> noRepeatTeacherIds = classGroupTeacherMapperList.stream().map(ClassGroupTeacherMapper::getUserId).collect(Collectors.toSet());
        if (noRepeatTeacherIds.size() != classGroupTeacherMapperList.size()) {
            throw new BizException("主教与助教存在冲突");
        }
        List<Integer> classGroupIds = mergeClassSplitClassAffirmDto.getClassGroupIds();
        if (classGroupIds == null || classGroupIds.size() == 0) {
            throw new BizException("请填写班级信息");
        }
        //所选班级列表，是否包含已冻结的班级
        List<ClassGroup> lockClassGroupIds = classGroupDao.findByClassGroupIds(classGroupIds, 1);
        if (lockClassGroupIds != null && lockClassGroupIds.size() > 0) {
            throw new BizException("所选班级包含审核中的学员班级调整申请");
        }
        //所选班级不能有未开始的临时合并课程
        int courseNum = courseScheduleDao.findNoStartMasterCourseNum(classGroupIds);
        if (courseNum > 0) {
            throw new BizException("所选班级不能有未开始的临时合并课程");
        }
        List<Integer> allTeacherIds = classGroupTeacherMapperList.stream()
                .map(ClassGroupTeacherMapper::getUserId)
                .collect(Collectors.toList());
        //所有教师列表
        List<Teacher> teachers = teacherDao.findByTeacherIds(allTeacherIds);
        Map<Integer, Teacher> teacherMap = teachers.stream()
                .collect(Collectors.toMap(Teacher::getId, teacher -> teacher));
        for (ClassGroupTeacherMapper classGroupTeacherMapper : classGroupTeacherMapperList) {
            List<TeacherDefaultMusicGroupSalary> teacherSalaryList = teacherDefaultMusicGroupSalaryService.getTeacherSalaryByUserIdAndType(classGroupTeacherMapper.getUserId(), null, null);

            Map<CourseSchedule.CourseScheduleType, TeacherDefaultMusicGroupSalary> collect = teacherSalaryList.stream().collect(Collectors.toMap(TeacherDefaultMusicGroupSalary::getCourseScheduleType, teacherDefaultMusicGroupSalary -> teacherDefaultMusicGroupSalary));

            TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalary = collect.get(classGroup4MixDto.getCourseType());
            Teacher teacher = teacherMap.get(classGroupTeacherMapper.getUserId());
            if (teacherDefaultMusicGroupSalary == null) {
                throw new BizException("请设置" + teacher.getRealName() + "老师的" + classGroup4MixDto.getCourseType().getMsg() + "课酬");
            }
            if ((classGroup4MixDto.getCourseType().equals(CourseSchedule.CourseScheduleType.HIGH_ONLINE) ||
                    classGroup4MixDto.getCourseType().equals(CourseSchedule.CourseScheduleType.MUSIC_NETWORK)) &&
                    StringUtils.isBlank(teacherDefaultMusicGroupSalary.getSalaryRuleJson())) {
                throw new BizException("请设置" + teacher.getRealName() + "老师的" + classGroup4MixDto.getCourseType().getMsg() + "课酬");
            } else if (teacherDefaultMusicGroupSalary.getAssistantTeacher30MinSalary() == null
                    || teacherDefaultMusicGroupSalary.getAssistantTeacher90MinSalary() == null
                    || teacherDefaultMusicGroupSalary.getMainTeacher30MinSalary() == null
                    || teacherDefaultMusicGroupSalary.getMainTeacher90MinSalary() == null) {
                throw new BizException("请设置" + teacher.getRealName() + "老师的" + classGroup4MixDto.getCourseType().getMsg() + "课酬");
            }
        }
    }

    @Override
    public Map<String, Long> findClassCourseMinuteMap(List<Integer> classGroupIds, Map<String, Long> classCourseMinuteMap) {
        Map<String, Long> resultMap = new HashMap<>();
        //获取所选班级最大剩余课时
        Map<String, Long> map = MapUtil.convertIntegerMap(courseScheduleDao.findClassMaxCourseNumMap(classGroupIds));
        Set<String> courseTypes = map.keySet();
        for (String courseType : courseTypes) {
//            剩余时长*默认排课时长
            resultMap.put(courseType, classCourseMinuteMap.get(courseType) * map.get(courseType));
        }
        return resultMap;
    }

    @Override
    public HighClassGroupNumDto getSubjectMaxHighClassGroupNum(String musicGroupId, ClassGroupTypeEnum type) {
        //基础技能班和线上基础技能班，可分班原则为声部人数/6向上取整
        List<StudentRegistration> musicGroupStudents = studentRegistrationDao.findMusicGroupStudent(musicGroupId, null);
        Map<Integer, List<StudentRegistration>> regMap = musicGroupStudents.stream().collect(Collectors.groupingBy(StudentRegistration::getActualSubjectId));
        int maxClassGroupNum = 0;
        int otherSubjectRegNum = 0;
        for (Map.Entry<Integer, List<StudentRegistration>> regEntry : regMap.entrySet()) {
            //上低音号、长号 合并计算
            if (regEntry.getKey().equals(14) || regEntry.getKey().equals(15)) {
                otherSubjectRegNum += regEntry.getValue().size();
                continue;
            }
            int classNum = regEntry.getValue().size() / 6;
            classNum += (regEntry.getValue().size() % 6) > 0 ? 1 : 0;
            maxClassGroupNum += classNum;
        }
        maxClassGroupNum += otherSubjectRegNum / 6;
        maxClassGroupNum += (otherSubjectRegNum % 6) > 0 ? 1 : 0;

        HighClassGroupNumDto highClassGroupNumDto = new HighClassGroupNumDto();
        int nowClassGroupNum = classGroupDao.getMusicGroupHighClassNumBySubject(musicGroupId, type);

        highClassGroupNumDto.setNowHighClassGroupNum(nowClassGroupNum);
        highClassGroupNumDto.setMaxHighClassGroupNum(maxClassGroupNum);
        return highClassGroupNumDto;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public List<MusicGroupPaymentCalenderStudentDetail> queryStudentPaymentCalenders(Integer masterClassGroupId,String classGroupStudentMap,List<Integer> studentIds) {
        //获取主班剩余课程时长
        Map<String, BigDecimal> masterMap = MapUtil.convertIntegerMap(courseScheduleDao.querySubCourseTimeMap(masterClassGroupId));
        if(masterMap.size() <= 0){
            throw new BizException("所选主班没有剩余课程，请重新选择");
        }
        //获取学员列表
        Map<Integer, String> userNames = MapUtil.convertMybatisMap(teacherDao.queryUsernameByIds(studentIds));
        Map<Integer, String> phoneMaps = MapUtil.convertMybatisMap(teacherDao.queryPhoneByIds(StringUtils.join(studentIds,",")));

        Map<Integer, Integer> studentCLassMap = new HashMap<>();
        List<Map<Integer, BigDecimal>> surplusCourseFeeMapList = new ArrayList<>();
        List<Map<String,String>> classGroupStudents = (List<Map<String,String>>)JSON.parse(classGroupStudentMap);
        for (Map<String, String> classGroupStudent : classGroupStudents) {
            for (String integer : classGroupStudent.keySet()) {
                //获取学员剩余课程费用
                surplusCourseFeeMapList.addAll(studentRegistrationDao.querySurplusCourseFeeByClassGroupId(Integer.parseInt(integer),classGroupStudent.get(integer)));
                String[] s = classGroupStudent.get(integer).split(",");
                for (String s1 : s) {
                    studentCLassMap.put(Integer.parseInt(s1),Integer.parseInt(integer));
                }
            }
        }
        //学员剩余课程费用
        Map<Integer, BigDecimal> surplusCourseFeeMap = MapUtil.convertIntegerMap(surplusCourseFeeMapList);
        //获取分布默认的课程类型单价
        MusicGroup musicGroup = musicGroupDao.findByClassGroupId(masterClassGroupId);
        Map<String, BigDecimal> unitPriceMap = MapUtil.convertIntegerMap(organizationCourseUnitPriceSettingsDao.queryMapByOrganIdAndChargeTypeId(musicGroup.getChargeTypeId(), musicGroup.getOrganId()));
        Set<String> masterKeySet = masterMap.keySet();
        //计算主班课程类型剩余价值
        Map<String, BigDecimal> masterTotalPriceMap = new HashMap<>(masterKeySet.size());
        //学员缴费项目列表
        List<MusicGroupPaymentCalenderStudentDetail> musicGroupPaymentCalenderStudentDetails = new ArrayList<>();
        for (String s : masterKeySet) {
            BigDecimal unitPrice = unitPriceMap.get(s);
            if (unitPrice == null) {
                throw new BizException("分部默认课程类型单价不存在，请设置");
            }
            BigDecimal courseTime = masterMap.get(s);
            //获取主班剩余课程价值，按分部默认单价计算
            //总价四舍五入取整
            BigDecimal totalPrice = unitPrice.multiply(courseTime).setScale(0, BigDecimal.ROUND_HALF_UP);
            masterTotalPriceMap.put(s,totalPrice);
            //课程余额转移
            for (Integer studentId : studentCLassMap.keySet()) {
                //学员剩余课程余额
                BigDecimal bigDecimal = surplusCourseFeeMap.get(studentId);
                //创建学员缴费项目
                MusicGroupPaymentCalenderStudentDetail calenderDto = new MusicGroupPaymentCalenderStudentDetail();
                calenderDto.setClassGroupId(studentCLassMap.get(studentId));
                //如果剩余课程余额小于等于0
                if(bigDecimal.doubleValue() <= 0d){
                    calenderDto.setCourseCurrentPrice(totalPrice);
                    calenderDto.setCourseOriginalPrice(totalPrice);
                }else {
                    //如果剩余课程余额大于等于总价值，那么补交0元
                    if(bigDecimal.doubleValue() >= totalPrice.doubleValue()){
                        calenderDto.setCutAmount(totalPrice);
                        calenderDto.setCourseCurrentPrice(BigDecimal.ZERO);
                        calenderDto.setCourseOriginalPrice(BigDecimal.ZERO);
                    }else {
                        calenderDto.setCourseCurrentPrice(totalPrice.subtract(bigDecimal));
                        calenderDto.setCutAmount(bigDecimal);
                        calenderDto.setCourseOriginalPrice(totalPrice.subtract(bigDecimal));
                    }
                    //剩余课程余额减去主班对应课程类型总的课程价值，负数就是需要补交的金额
//                    bigDecimal = bigDecimal.subtract(totalPrice);
                    surplusCourseFeeMap.put(studentId,bigDecimal.subtract(totalPrice));
                }
                calenderDto.setCourseTime(courseTime.intValue());
                calenderDto.setCourseType(s);

                calenderDto.setPhone(phoneMaps.get(studentId));
                calenderDto.setUserId(studentId);
                calenderDto.setUsername(userNames.get(studentId));
                musicGroupPaymentCalenderStudentDetails.add(calenderDto);
            }
        }
        return musicGroupPaymentCalenderStudentDetails;
    }


    @Override
    public BigDecimal getMasterTotalPrice(Integer masterClassGroupId) {
        //获取主班剩余时长
        Map<String, BigDecimal> masterMap = MapUtil.convertIntegerMap(courseScheduleDao.querySubCourseTimeMap(masterClassGroupId));
        if(masterMap.size() <= 0){
            throw new BizException("所选主班没有剩余课程，请重新选择");
        }
        //获取分布默认的课程类型单价
        MusicGroup musicGroup = musicGroupDao.findByClassGroupId(masterClassGroupId);
        Map<String, BigDecimal> unitPriceMap = MapUtil.convertIntegerMap(organizationCourseUnitPriceSettingsDao.queryMapByOrganIdAndChargeTypeId(musicGroup.getChargeTypeId(), musicGroup.getOrganId()));
        Set<String> masterKeySet = masterMap.keySet();
        //计算主班课程类型剩余价值
        BigDecimal masterTotalPrice = BigDecimal.ZERO;
        for (String s : masterKeySet) {
            BigDecimal unitPrice = unitPriceMap.get(s);
            if (unitPrice == null) {
                throw new BizException("分部默认课程类型单价不存在，请设置");
            }
            BigDecimal courseTime = masterMap.get(s);
            //获取主班剩余课程价值，按分部默认单价计算
            //总价四舍五入取整
            BigDecimal totalPrice = unitPrice.multiply(courseTime).setScale(0, BigDecimal.ROUND_HALF_UP);
            masterTotalPrice = masterTotalPrice.add(totalPrice);
        }
        return masterTotalPrice;
    }

    @Override
    public Map<String, Long> querySubCourseTime(Integer classGroupId) {
        return MapUtil.convertIntegerMap(courseScheduleDao.querySubCourseNumMap(classGroupId));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResponseResult spanGroupMergeClassSplitClassAffirm(MergeClassSplitClassAffirmDto mergeClassSplitClassAffirmDto) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        //缴费项目
        MusicGroupPaymentCalenderDto paymentCalenderDto = mergeClassSplitClassAffirmDto.getMusicGroupPaymentCalenderDtos().get(0);
        //主班
        Integer masterClassGroupId = mergeClassSplitClassAffirmDto.getMasterClassGroupId();
        //学员列表
        List<Integer> studentIds = mergeClassSplitClassAffirmDto.getStudentIds();
        //主班是否包含所选学员列表
        Boolean hasStudent = classGroupStudentMapperDao.hasStudent(masterClassGroupId,studentIds);
        if(hasStudent){
            throw new BizException("操作失败: 主班包含部分已选学员");
        }
        //学员列表
        List<Integer> classGroupIds = mergeClassSplitClassAffirmDto.getClassGroupIds();
        //班级和学员关联
        List<Map<Integer, String>> classGroupStudents = mergeClassSplitClassAffirmDto.getClassGroupStudents();
        //获取默认的学员缴费详情
        List<MusicGroupPaymentCalenderStudentDetail> musicGroupPaymentCalenderStudentDetails = queryStudentPaymentCalenders(masterClassGroupId,
                JSON.toJSONString(mergeClassSplitClassAffirmDto.getClassGroupStudents()),
                studentIds);
        //创建缴费项目
        MusicGroup musicGroup = musicGroupDao.findByClassGroupId(masterClassGroupId);
        BigDecimal masterTotalPrice = getMasterTotalPrice(masterClassGroupId);
        //是否有需要审核的缴费项目
        List<MusicGroupPaymentCalenderStudentDetail> calenderStudentDetails = paymentCalenderDto.getMusicGroupPaymentCalenderStudentDetails();

        paymentCalenderDto.setMusicGroupId(musicGroup.getId());
        boolean containsAll = musicGroupPaymentCalenderStudentDetails.containsAll(calenderStudentDetails);
        if(!containsAll){
            paymentCalenderDto.setStatus(AUDITING);
        }else {
            paymentCalenderDto.setStatus(NO);
        }

        //将学员加入新乐团、扣除原乐团剩余课程余额、补充到现有乐团
        Map<Integer, List<MusicGroupPaymentCalenderStudentDetail>> collect = calenderStudentDetails.stream().collect(Collectors.groupingBy(e -> e.getUserId()));
        for (Map<Integer, String> classGroupStudent : classGroupStudents) {
            Integer classGroupId = classGroupStudent.keySet().iterator().next();
            studentRegistrationService.insertStudent(classGroupStudent.get(classGroupId),musicGroupDao.findByClassGroupId(classGroupId).getId(),musicGroup.getId(),collect);
        }
        paymentCalenderDto.setPayUserType(MusicGroupPaymentCalender.PayUserType.STUDENT);
        paymentCalenderDto.setPaymentType(SPAN_GROUP_CLASS_ADJUST);
        //生成缴费项目
        paymentCalenderDto.setMasterTotalPrice(masterTotalPrice);
        paymentCalenderDto.setIsGiveMusicNetwork(false);
        paymentCalenderDto.setStudentIds(StringUtils.join(studentIds,","));
        musicGroupPaymentCalenderService.create(paymentCalenderDto);
        //记录申请信息
        MusicGroupStudentClassAdjust musicGroupStudentClassAdjust = new MusicGroupStudentClassAdjust();
        musicGroupStudentClassAdjust.setMasterClassGroupId(masterClassGroupId);
        musicGroupStudentClassAdjust.setBatchNo(paymentCalenderDto.getBatchNo());
        musicGroupStudentClassAdjust.setMusicGroupId(musicGroup.getId());
        musicGroupStudentClassAdjust.setOperatorId(sysUser.getId());
        musicGroupStudentClassAdjust.setClassGroupIds(JSON.toJSONString(classGroupIds));
        musicGroupStudentClassAdjust.setStudentIds(JSON.toJSONString(studentIds));
        musicGroupStudentClassAdjust.setMasterTotalPrice(masterTotalPrice);
        musicGroupStudentClassAdjust.setMasterClassCourseTimes(courseScheduleDao.queryTotalCourseTimes(masterClassGroupId));
        if (classGroupStudents != null && classGroupStudents.size() > 0) {
            musicGroupStudentClassAdjust.setClassGroupStudents(JSON.toJSONString(mergeClassSplitClassAffirmDto.getClassGroupStudents()));
        }
        //获取需要删除的学员关联的课程
        List<Long> courseIds = courseScheduleDao.queryStudentNotStartByClassIdsAndStudentIds(classGroupIds, studentIds);
        musicGroupStudentClassAdjust.setSubLockCourseIds(JSON.toJSONString(courseIds));
        //获取关联的学员缴费信息
        List<Long> studentPaymentIds = courseScheduleStudentPaymentDao.queryStudentNotStartByClassIdsAndStudentIds(classGroupIds, studentIds);
        musicGroupStudentClassAdjust.setStudentPaymentIds(JSON.toJSONString(studentPaymentIds));
        //获取需要冻结的课程
        classGroupIds.add(masterClassGroupId);
        //所选班级列表，是否包含已冻结的班级
        List<ClassGroup> lockClassGroupIds = classGroupDao.findByClassGroupIds(classGroupIds, 1);
        if (lockClassGroupIds != null && lockClassGroupIds.size() > 0) {
            throw new BizException("所选班级包含审核中的学员班级调整申请");
        }
        //所选班级不能有未开始的临时合并课程
        int courseNum = courseScheduleDao.findNoStartMasterCourseNum(classGroupIds);
        if (courseNum > 0) {
            throw new BizException("所选班级不能有未开始的临时合并课程");
        }
        List<Long> allLockCourseIds = courseScheduleDao.queryStudentNotStartByClassIdsAndStudentIds(classGroupIds, null);
        musicGroupStudentClassAdjust.setAllLockCourseIds(JSON.toJSONString(allLockCourseIds));
        musicGroupStudentClassAdjustDao.insert(musicGroupStudentClassAdjust);
        HttpResponseResult httpResponseResult = new HttpResponseResult();
        httpResponseResult.setCode(200);
        httpResponseResult.setStatus(true);
        //没有需要审核的缴费项目
        if (paymentCalenderDto.getStatus() != AUDITING) {
            List<Map> classGroupStudents1 = JSON.parseArray(musicGroupStudentClassAdjust.getClassGroupStudents(),Map.class);
            spanGroupClassAdjustPass(masterClassGroupId,studentIds,courseIds,classGroupStudents1,allLockCourseIds,paymentCalenderDto.getBatchNo(),masterTotalPrice);
            httpResponseResult.setMsg("操作成功：学员班级调整完成");
        }else {
//                冻结班级
            classGroupDao.batchUpdateLockByClassGroupIds(classGroupIds, 1);
//                冻结所选班级的课程
            courseScheduleDao.batchUpdateLockByCourseIds(allLockCourseIds, 1);
            httpResponseResult.setMsg("操作成功：学员班级调整申请已提交,缴费项目审核中");
        }
        return httpResponseResult;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void spanGroupClassAdjustPass(Integer masterClassGroupId,
                                         List<Integer> studentIds,
                                         List<Long> courseIds,
                                         List<Map> classGroupStudents,
                                         List<Long> allLockCourseIds,
                                         String batchNo,BigDecimal masterTotalPrice){
        //删除班级关联的学员
        List<Integer> classGroupIds = new ArrayList<>();
        if (classGroupStudents != null && classGroupStudents.size() > 0) {
            for (Map<Integer, String> classGroupStudent : classGroupStudents) {
                Set<Integer> integers = classGroupStudent.keySet();
                for (Integer integer : integers) {
                    List<Integer> collect = Arrays.asList(classGroupStudent.get(integer).split(",")).stream().map(e -> Integer.parseInt(e)).collect(Collectors.toList());
                    //学员退出群聊
                    imGroupMemberService.quit(integer.longValue(),collect);
                    classGroupIds.add(integer);
                    classGroupStudentMapperDao.deleteByClassGroupIdAndStudents(integer, classGroupStudent.get(integer));
                }
            }
        }

        //将学员加进班级未开始的课程，以及班级关联、加群
        classGroupStudentMapperService.updateClassGroupStudents1(masterClassGroupId.longValue(),studentIds,allLockCourseIds,batchNo,masterTotalPrice);
        //删除学员课程
        if(courseIds.size() > 0){
            courseScheduleDao.deleteMusicGroupCourseSchedulesWithStudents(courseIds, studentIds);
        }
        //解冻课程
        courseScheduleDao.batchUpdateLockByCourseIds(allLockCourseIds,0);
        //解冻班级
        classGroupIds.add(masterClassGroupId);
        classGroupDao.batchUpdateLockByClassGroupIds(classGroupIds,0);
        if(courseIds.size() > 0){
            //获取没有学员的课程
            List<Long> delCourseIds = courseScheduleDao.findNoStudentCourseIds(courseIds);
            if (delCourseIds != null && delCourseIds.size() > 0) {
                //删除课程
                courseScheduleDao.deleteCourseSchedulesByClassGroupIds(delCourseIds);
                //删除教师考勤
                teacherAttendanceDao.batchDeleteByCourseSchedules(delCourseIds);
                //删除教师课酬
                courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(delCourseIds);
            }
        }
    }
}
