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

import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.TeacherSalaryDto;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.dal.page.CourseScheduleTeacherSalaryQueryInfo;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.constant.CommonConstants;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

@Service
public class CourseScheduleTeacherSalaryServiceImpl extends BaseServiceImpl<Long, CourseScheduleTeacherSalary> implements CourseScheduleTeacherSalaryService {

    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
    private VipGroupActivityDao vipGroupActivityDao;
    @Autowired
    private CourseScheduleComplaintsDao courseScheduleComplaintsDao;
    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
    private SysUserCashAccountService sysUserCashAccountService;
    @Autowired
    private VipGroupService vipGroupService;
    @Autowired
    private SchoolService schoolService;
    @Autowired
    private CourseScheduleDao courseScheduleDao;
    @Autowired
    private TeacherDefaultMusicGroupSalaryDao teacherDefaultMusicGroupSalaryDao;
    @Autowired
    private SysUserCashAccountDetailDao sysUserCashAccountDetailDao;
    @Autowired
    private SysConfigService sysConfigDao;
    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;
    @Autowired
    private ClassGroupDao classGroupDao;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;
    @Autowired
    private ClassGroupTeacherSalaryDao classGroupTeacherSalaryDao;
    @Autowired
    private TeacherDefaultVipGroupSalaryDao teacherDefaultVipGroupSalaryDao;
    @Autowired
    private VipGroupCategoryDao vipGroupCategoryDao;

    private static final Logger LOGGER = LoggerFactory
            .getLogger(CourseScheduleTeacherSalaryServiceImpl.class);

    @Override
    public BaseDAO<Long, CourseScheduleTeacherSalary> getDAO() {
        return courseScheduleTeacherSalaryDao;
    }

    @Override
    public void createCourseScheduleTeacherVipSalary(VipGroup vipGroup,
                                                     List<CourseSchedule> vipCourseSchedules,
                                                     BigDecimal onlineTeacherSalary,
                                                     BigDecimal offlineTeacherSalary) {

        School school = schoolService.get(vipGroup.getTeacherSchoolId());
        BigDecimal subsidy = new BigDecimal(0);
        if (Objects.nonNull(school)) {
            subsidy=school.getSubsidy();
        }

        //获取活动信息
        VipGroupActivity vipGroupActivity = null;
        if(vipGroup.getVipGroupActivityId() != null){
        	vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());
        }

        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = new ArrayList<>();
        Map<TeachModeEnum, List<CourseSchedule>> courseScheduleGroupByTeachMode = vipCourseSchedules.stream().collect(Collectors.groupingBy(CourseSchedule::getTeachMode));

        for (TeachModeEnum teachModeEnum : courseScheduleGroupByTeachMode.keySet()) {
            List<CourseSchedule> courseSchedules = courseScheduleGroupByTeachMode.get(teachModeEnum)
                    .stream()
                    .sorted(Comparator.comparing(CourseSchedule::getStartClassTime)).collect(Collectors.toList());
            for (int i = 0; i < courseSchedules.size(); i++) {
                //创建教师课程薪水记录
                CourseScheduleTeacherSalary courseScheduleTeacherSalary = courseScheduleTeacherSalaryDao.queryByCourseScheduleIdAndUserId(courseSchedules.get(i).getId(), courseSchedules.get(i).getActualTeacherId());
                if (Objects.isNull(courseScheduleTeacherSalary)) {
                    courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
                }
                courseScheduleTeacherSalary.setCourseScheduleId(courseSchedules.get(i).getId());
                courseScheduleTeacherSalary.setGroupType(courseSchedules.get(i).getGroupType());
                courseScheduleTeacherSalary.setMusicGroupId(courseSchedules.get(i).getMusicGroupId());
                courseScheduleTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
                courseScheduleTeacherSalary.setUserId(courseSchedules.get(i).getActualTeacherId().intValue());
                courseScheduleTeacherSalary.setClassGroupId(courseSchedules.get(i).getClassGroupId());
                courseScheduleTeacherSalary.setSubsidy(subsidy);

                if (Objects.nonNull(vipGroupActivity)
                        &&vipGroupActivity.getType() == VipGroupActivityTypeEnum.GIVE_CLASS
                        && vipGroup.getGiveTeachMode() == teachModeEnum
                        && i >= Integer.parseInt(vipGroupActivity.getAttribute1())
                        && "0".equals(vipGroupActivity.getGiveClassPaySalaryFlag())) {
                    courseScheduleTeacherSalary.setExpectSalary(new BigDecimal(0));
                } else {
                    if (teachModeEnum == TeachModeEnum.ONLINE) {
                        courseScheduleTeacherSalary.setExpectSalary(onlineTeacherSalary);
                    } else {
                        courseScheduleTeacherSalary.setExpectSalary(offlineTeacherSalary);
                    }
                }
                if (Objects.isNull(courseScheduleTeacherSalary.getId())) {
                    courseScheduleTeacherSalaries.add(courseScheduleTeacherSalary);
                } else {
                    courseScheduleTeacherSalaryDao.update(courseScheduleTeacherSalary);
                }
            }
        }
        if (courseScheduleTeacherSalaries.size() > 0) {
            batchInsert(courseScheduleTeacherSalaries);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchInsert(List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries) {
        courseScheduleTeacherSalaryDao.batchInsert(courseScheduleTeacherSalaries);
        List<Long> courseScheduleIds = courseScheduleTeacherSalaries.stream()
                .map(CourseScheduleTeacherSalary::getCourseScheduleId)
                .collect(Collectors.toList());
        List<ClassGroup> byCourseSchedules = classGroupDao.findByCourseSchedules(courseScheduleIds);

        Map<Integer, ClassGroup> classGroupMap = new HashMap<Integer, ClassGroup>();
        for (ClassGroup classGroup : byCourseSchedules) {
            if (!classGroupMap.containsKey(classGroup.getId())) {
                classGroupMap.put(classGroup.getId(), classGroup);
            }
        }

        List<TeacherAttendance> teacherIdByCourseSchedule = teacherAttendanceDao.findTeacherIdByCourseSchedule(courseScheduleIds);
        Map<Long, List<TeacherAttendance>> courseScheduleTeacherAttendanceMap = teacherIdByCourseSchedule.stream()
                .collect(Collectors.groupingBy(TeacherAttendance::getCourseScheduleId));
        List<TeacherAttendance> teacherAttendances = new ArrayList<>();
        courseScheduleTeacherSalaries.forEach(courseScheduleTeacherSalary -> {
            List<TeacherAttendance> teacherAttendancesTemp = courseScheduleTeacherAttendanceMap.get(courseScheduleTeacherSalary.getCourseScheduleId());
            List<Integer> collect = new ArrayList<>();
            if (!CollectionUtils.isEmpty(teacherAttendancesTemp)) {
                collect = teacherAttendancesTemp.stream().map(TeacherAttendance::getTeacherId).collect(Collectors.toList());
            }
            TeacherAttendance teacherAttendance = new TeacherAttendance();
            teacherAttendance.setGroupType(courseScheduleTeacherSalary.getGroupType());
            teacherAttendance.setClassGroupId(courseScheduleTeacherSalary.getClassGroupId());
            teacherAttendance.setMusicGroupId(courseScheduleTeacherSalary.getMusicGroupId());
            if (CollectionUtils.isEmpty(collect) || !collect.contains(courseScheduleTeacherSalary.getUserId())) {
                teacherAttendance.setTeacherId(courseScheduleTeacherSalary.getUserId());
                teacherAttendance.setCourseScheduleId(courseScheduleTeacherSalary.getCourseScheduleId());
                teacherAttendances.add(teacherAttendance);
            }
        });
        if (!CollectionUtils.isEmpty(teacherAttendances)) {
            teacherAttendanceDao.batchInsert(teacherAttendances);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void teacherSalarySettlement() {

        int days = Integer.parseInt(sysConfigDao.findByParamName(SysConfigService.VIP_APPEAL_DAYS_RANGE).getParanValue());

        BigDecimal percent = new BigDecimal(10);

        //获取教师未结算课程记录
        List<CourseScheduleTeacherSalary> someDayAgoTeacherCourseSalaryNoSettlement = courseScheduleTeacherSalaryDao.findSomeDayAgoTeacherCourseSalaryNoSettlement(days);
        if (CollectionUtils.isEmpty(someDayAgoTeacherCourseSalaryNoSettlement)) {
            LOGGER.info("未获取到未结算课酬记录!");
            return;
        }
        Date now = new Date();
        //获取未结算课程编号列表
        List<Long> courseScheduleIds = someDayAgoTeacherCourseSalaryNoSettlement.stream().map(CourseScheduleTeacherSalary::getCourseScheduleId).collect(Collectors.toList());
        //获取未结算课程投诉记录
        List<CourseScheduleComplaints> courseScheduleComplaints = courseScheduleComplaintsDao.findByCourseScheduleIds(courseScheduleIds);
        //获取未结算课程学生缴费信息
        List<CourseScheduleStudentPayment> courseScheduleStudentPayments = courseScheduleStudentPaymentDao.findByCourseScheduleIds(courseScheduleIds);

        //根据课程将投诉信息分组
        Map<Long, List<CourseScheduleComplaints>> complaintsGroupByCourse = courseScheduleComplaints.stream().collect(Collectors.groupingBy(CourseScheduleComplaints::getCourseScheduleId));
        //根据课程将学生缴费信息分组
        Map<Long, List<CourseScheduleStudentPayment>> studentPaymentGroupByCourse = courseScheduleStudentPayments.stream().collect(Collectors.groupingBy(CourseScheduleStudentPayment::getCourseScheduleId));

        //需更新教师课程结算记录
        List<CourseScheduleTeacherSalary> updateTeacherSalarys = new ArrayList<>();
        //需更新学生课程缴费记录
        List<CourseScheduleStudentPayment> updateStudentPayments = new ArrayList<>();

        //用户账户资金变动信息列表
        List<SysUserCashAccountDetail> userCashAccountDetails = new ArrayList<>();

        //处理课酬信息
        someDayAgoTeacherCourseSalaryNoSettlement.forEach(courseScheduleTeacherSalary -> {
            //获取当前课程学生缴费记录
            List<CourseScheduleStudentPayment> studentPaymentsWithCourse = studentPaymentGroupByCourse.get(courseScheduleTeacherSalary.getCourseScheduleId());

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

            //当前课程缴费学生数量
            BigDecimal courseStudentNum = new BigDecimal(studentPaymentsWithCourse.size());

            //教师预计课酬
            BigDecimal expectSalary = courseScheduleTeacherSalary.getExpectSalary();
            //当前课程每个学生平均课酬
            BigDecimal avgSalary = expectSalary.divide(courseStudentNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
            //教师当前课程责任总占比,当前课程应得课酬
            BigDecimal teacherLiabilityAllratio;

            //当前课程学生投诉记录
            List<CourseScheduleComplaints> courseStudentComplaints = complaintsGroupByCourse.get(courseScheduleTeacherSalary.getCourseScheduleId());

            //如果存在投诉记录,需要扣除相应费用
            if (Objects.nonNull(courseStudentComplaints)) {
                //获取审批中的投诉
                List<CourseScheduleComplaints> auditIng = courseStudentComplaints.stream().filter(courseScheduleComplaint -> courseScheduleComplaint.getStatus() == AuditStatusEnum.ING).collect(Collectors.toList());
                if (!CollectionUtils.isEmpty(auditIng)) {
                    //如果当前课程存在未处理的投诉，则不做结算处理
                    return;
                }
                //计算教师责任总占比
                double teacherLiabilityRatioSum = courseStudentComplaints.stream().mapToDouble(courseScheduleComplaint -> Objects.isNull(courseScheduleComplaint.getTeacherLiabilityRatio()) ? 0 : courseScheduleComplaint.getTeacherLiabilityRatio()).sum();
                teacherLiabilityAllratio = new BigDecimal(teacherLiabilityRatioSum).divide(percent,CommonConstants.DECIMAL_PLACE,BigDecimal.ROUND_DOWN);
            } else {
                //如果没有投诉，则教师和学生的责任占比为0
                teacherLiabilityAllratio = new BigDecimal(0);
            }

            //教师应扣除费用
            BigDecimal deductPrice = avgSalary.multiply(teacherLiabilityAllratio);
            //教师实际课酬
            BigDecimal schoolSubsidy = new BigDecimal(0);
            if (Objects.nonNull(courseScheduleTeacherSalary.getSubsidy())) {
                schoolSubsidy = courseScheduleTeacherSalary.getSubsidy();
            }
            BigDecimal actualSalary = expectSalary.subtract(deductPrice).add(schoolSubsidy);

            //更新教师结算信息
            courseScheduleTeacherSalary.setActualSalary(actualSalary);
            courseScheduleTeacherSalary.setSettlementTime(now);
            courseScheduleTeacherSalaryDao.update(courseScheduleTeacherSalary);
            updateTeacherSalarys.add(courseScheduleTeacherSalary);

            //生成教师账户资金变动记录
            sysUserCashAccountService.updateBalance(courseScheduleTeacherSalary.getUserId(), actualSalary);
            SysUserCashAccount teacherCashAccount = sysUserCashAccountService.get(courseScheduleTeacherSalary.getUserId().intValue());
            SysUserCashAccountDetail teacherCashAccountDetail = new SysUserCashAccountDetail();
            teacherCashAccountDetail.setUserId(courseScheduleTeacherSalary.getUserId());
            teacherCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.WAGE);
            teacherCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
            teacherCashAccountDetail.setAmount(actualSalary);
            if(Objects.isNull(teacherCashAccount)){
                teacherCashAccountDetail.setBalance(new BigDecimal(0));
            }else{
                teacherCashAccountDetail.setBalance(teacherCashAccount.getBalance());
            }
            teacherCashAccountDetail.setAttribute(courseScheduleTeacherSalary.getCourseScheduleId().toString());

            userCashAccountDetails.add(teacherCashAccountDetail);

            //根据学生进行投诉分组
            Map<Integer, List<CourseScheduleComplaints>> complainsGroupByStudent = null;
            if (Objects.nonNull(courseStudentComplaints)) {
                complainsGroupByStudent = courseStudentComplaints.stream().collect(Collectors.groupingBy(CourseScheduleComplaints::getUserId));
            }

            BigDecimal zero=new BigDecimal(0);

            //计算学生当前课程应缴费用
            for (CourseScheduleStudentPayment studentPayment : studentPaymentsWithCourse) {
                //当前课程学生应缴费用
                BigDecimal studentExpectPrice = studentPayment.getExpectPrice();
                if (Objects.isNull(studentExpectPrice)) {
                    studentExpectPrice = new BigDecimal(0);
                }
                //当前课程学生责任占比
                BigDecimal studentLiabilityRatio;
                List<CourseScheduleComplaints> currentCourseScheduleComplaints = null;
                if (!CollectionUtils.isEmpty(complainsGroupByStudent)) {
                    currentCourseScheduleComplaints = complainsGroupByStudent.get(studentPayment.getUserId());
                }
                if (!CollectionUtils.isEmpty(currentCourseScheduleComplaints)) {
                    Double temp = currentCourseScheduleComplaints.get(0).getStudentLiabilityRatio();
                    if (Objects.isNull(temp)) {
                        temp = 0.0;
                    }
                    studentLiabilityRatio = new BigDecimal(temp).divide(percent,CommonConstants.DECIMAL_PLACE,BigDecimal.ROUND_DOWN);
                } else {
                    studentLiabilityRatio = new BigDecimal(1);
                }


                //当前课程学生实际缴费
                BigDecimal actualPrice = studentExpectPrice.multiply(studentLiabilityRatio);
                //当前课程学生应退费用
                BigDecimal returnPrice = studentExpectPrice.subtract(actualPrice);
                //更新学生结算信息
                studentPayment.setActualPrice(actualPrice);
                studentPayment.setSettlementTime(now);
                courseScheduleStudentPaymentDao.update(studentPayment);
                updateStudentPayments.add(studentPayment);


                if(returnPrice.compareTo(zero)!=0){
                    //生成学生账户资金变动记录
                    sysUserCashAccountService.updateBalance(studentPayment.getUserId(), returnPrice);
                    SysUserCashAccount studentCashAccount = sysUserCashAccountService.get(studentPayment.getUserId().intValue());
                    SysUserCashAccountDetail studentAccountDetail = new SysUserCashAccountDetail();
                    studentAccountDetail.setUserId(studentPayment.getUserId());
                    studentAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
                    studentAccountDetail.setStatus(DealStatusEnum.SUCCESS);
                    studentAccountDetail.setAmount(returnPrice);
                    studentAccountDetail.setBalance(studentCashAccount.getBalance());
                    studentAccountDetail.setAttribute(courseScheduleTeacherSalary.getCourseScheduleId().toString());

                    userCashAccountDetails.add(studentAccountDetail);
                }
            }

        });
        if(!CollectionUtils.isEmpty(userCashAccountDetails)){
            sysUserCashAccountDetailDao.batchInsert(userCashAccountDetails);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicGroupTeacherSalarySettlement() {
        Date now = new Date();
        Date settleTime = DateUtil.addDays1(now, -sysConfigDao.findByParamName(SysConfigService.MUSIC_GROUP_SETTLEMENT_DAY).getParanValue(Integer.class));
        Integer settlementClassMinutes = Integer.parseInt(sysConfigDao.findByParamName(SysConfigService.MUSIC_GROUP_SETTLEMENT_CLASS_MINUTES).getParanValue());
        Integer singleClassTime = Integer.parseInt(sysConfigDao.findByParamName(SysConfigService.MUSIC_GROUP_SETTLEMENT_SINGLE_CLASS_MINUTES).getParanValue());
        Date entryDate = DateUtil.stringToDate(sysConfigDao.findByParamName(SysConfigService.TEACHER_ENTRY_DATE).getParanValue(),"yyyy-MM-dd");
        //获取昨天的课程计划
        List<CourseSchedule> yesterdayCourseSchedules = courseScheduleDao.findCourseScheduleWithDate(settleTime);
        //课程编号列表
        List<Long> courseScheduleIds = yesterdayCourseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(courseScheduleIds)) {
            return;
        }
        //获取课程对应教学点补贴
        List<Map<Integer, BigDecimal>> courseSubsidyByCourses = courseScheduleTeacherSalaryDao.findCourseSubsidyByCourses(courseScheduleIds);
        Map<Integer, BigDecimal> courseSubsidyMap = MapUtil.convertIntegerMap(courseSubsidyByCourses);

        //课程编号与课程对应集合
        Map<Long, CourseSchedule> courseScheduleIdMap = yesterdayCourseSchedules.stream()
                .collect(Collectors.toMap(CourseSchedule::getId, courseSchedule -> courseSchedule));

        //课程教师课酬
        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByCourseSchedulesWithNoSettlement(courseScheduleIds);

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

        //课程对应乐团结算方式集合
        List<Map<String, String>> musicGroupSettlementTypeByCourse = courseScheduleTeacherSalaryDao.findMusicGroupSettlementTypeByCourse(courseScheduleIds);
        Map<String, String> musicGroupSettlementsMap = MapUtil.convertMybatisMap(musicGroupSettlementTypeByCourse);

        //教师对应课程列表集合
        Map<Integer, List<CourseScheduleTeacherSalary>> teacherSalarysByTeacher = courseScheduleTeacherSalaries.stream()
                .collect(Collectors.groupingBy(CourseScheduleTeacherSalary::getUserId));

        //所有老师编号
        List<Integer> allTeacherIds = courseScheduleTeacherSalaries.stream()
                .map(CourseScheduleTeacherSalary::getUserId)
                .collect(Collectors.toList());

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

        //所有老师默认乐团课酬
        List<TeacherDefaultMusicGroupSalary> teacherDefaultMusicGroupSalaries = teacherDefaultMusicGroupSalaryDao.findByTeacher(allTeacherIds);
        Map<CourseSchedule.CourseScheduleType, List<TeacherDefaultMusicGroupSalary>> teacherDefaultMusicGroupSalariesGroupByCourseType = teacherDefaultMusicGroupSalaries.stream().collect(Collectors.groupingBy(TeacherDefaultMusicGroupSalary::getCourseScheduleType));


        //教师对应的每个教学点的总课时
        Map<Integer, Map<Integer, Map<Date, Integer>>> teacherClassMinutesMap = new HashMap<>();
        //计算老师对应的总课时
        teacherSalarysByTeacher.forEach((teacherId, teacherSalarys) -> {
            //当前老师所在课程的编号列表
            List<Long> currentTeacherCourscheduleIds = teacherSalarys.stream()
                    .map(CourseScheduleTeacherSalary::getCourseScheduleId)
                    .collect(Collectors.toList());
            //当前老师的课程列表
            List<CourseSchedule> currentTeacherCourseSchedules = yesterdayCourseSchedules.stream()
                    .filter(courseSchedule -> currentTeacherCourscheduleIds.contains(courseSchedule.getId()))
                    .collect(Collectors.toList());
            //根据教学点将当前老师的课程分组
            Map<Integer, List<CourseSchedule>> schoolCourseSchedules = currentTeacherCourseSchedules.stream()
                    .filter(courseSchedule -> Objects.nonNull(courseSchedule.getSchoolId()))
                    .collect(Collectors.groupingBy(CourseSchedule::getSchoolId));
            Map<Integer, Map<Date,Integer>> schoolClassMinutesMap = new HashMap<>();
            for (Integer schoolId : schoolCourseSchedules.keySet()) {
                //当前教学点的课程
                List<CourseSchedule> currentSchoolCourseSchedules = schoolCourseSchedules.get(schoolId);
                Map<Date, List<CourseSchedule>> courseScheduleWithDate = currentSchoolCourseSchedules.stream()
                        .collect(Collectors.groupingBy(CourseSchedule::getClassDate));
                Map<Date,Integer> dataClassMinutesMpa = new HashMap<>();
                for (Date classDate:courseScheduleWithDate.keySet()){
                    Integer classMinutes = 0;
                    List<CourseSchedule> classCourses = courseScheduleWithDate.get(classDate);
                    for (CourseSchedule courseSchedule : classCourses) {
                        //如果课程为单机课或者为合奏课，则算入总课时长
                        if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.SINGLE)
                                || courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.MIX)) {
                            classMinutes += DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime());
                        }
                    }
                    dataClassMinutesMpa.put(classDate, classMinutes);
                }
                schoolClassMinutesMap.put(schoolId, dataClassMinutesMpa);
            }
            teacherClassMinutesMap.put(teacherId, schoolClassMinutesMap);
        });
        //用户账户自己变动信息列表
        List<SysUserCashAccountDetail> userCashAccountDetails = new ArrayList<>();
        //计算课酬
        courseScheduleTeacherSalaries.forEach(courseScheduleTeacherSalary -> {
            TeacherAttendance teacherAttendanceInfo = teacherAttendanceDao.findByTeacherAttendanceInfo(courseScheduleTeacherSalary.getUserId().longValue(), courseScheduleTeacherSalary.getCourseScheduleId());
            if(Objects.isNull(teacherAttendanceInfo)
                ||(Objects.isNull(teacherAttendanceInfo.getSignInTime())&&Objects.isNull(teacherAttendanceInfo.getSignOutTime()))){
                return;
            }
            boolean durationIsChange = false;
            //当前课酬对应的课程信息
            CourseSchedule courseSchedule = courseScheduleIdMap.get(courseScheduleTeacherSalary.getCourseScheduleId());
            Map<Integer, Map<Date,Integer>> schoolClassMinutesMap = teacherClassMinutesMap.get(courseScheduleTeacherSalary.getUserId());
            Map<Date,Integer> classDateMinutes = schoolClassMinutesMap.get(courseSchedule.getSchoolId());

            //结算方式
            String settlementType = musicGroupSettlementsMap.get(courseScheduleTeacherSalary.getCourseScheduleId());
            if(StringUtils.isEmpty(settlementType)){
                LOGGER.error("未指定课酬结算方式[{}]", courseScheduleTeacherSalary.getId());
            }
            Teacher teacher=teacherMap.get(courseScheduleTeacherSalary.getUserId());
            //如果当前教师是在指定日期之后入职的，则按照3.0的方式结算
            if(Objects.nonNull(teacher.getEntryDate())
                    &&(teacher.getEntryDate().after(entryDate)||teacher.getEntryDate().getTime()==entryDate.getTime())){
                settlementType = SalarySettlementTypeEnum.GRADIENT_SALARY.getCode();
            }

            //当前课程的时长
            int duration = DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime());
            //如果是单技课或者合奏课并且结算方式为3.0
            if (Objects.nonNull(classDateMinutes)&&settlementType.equals(SalarySettlementTypeEnum.GRADIENT_SALARY.getCode())
                    &&(courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.SINGLE)
                    || courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.MIX))) {
                Integer schoolClassMinutes = classDateMinutes.get(courseSchedule.getClassDate());
                if (schoolClassMinutes >= settlementClassMinutes && duration < singleClassTime) {
                    duration = singleClassTime;
                    durationIsChange = true;
                }
            }

            //教师课酬
            BigDecimal teacherSalary = new BigDecimal(0);

            if(durationIsChange){

                //根据课程类型获取对应的默认课酬设置列表
                List<TeacherDefaultMusicGroupSalary> teacherDefaultMusicGroupSalariesWithCourseType = teacherDefaultMusicGroupSalariesGroupByCourseType.get(courseSchedule.getType());
                if (CollectionUtils.isEmpty(teacherDefaultMusicGroupSalariesWithCourseType)) {
                    LOGGER.error("存在未指定结算方式的课程类型[{}]", courseScheduleTeacherSalary.getId());
                }

                //根据教师编号将对应结算方式下的默认课酬设置分组
                Map<Integer, TeacherDefaultMusicGroupSalary> teacherDefaultMusicGroupSalariesGroupByTeacherId = teacherDefaultMusicGroupSalariesWithCourseType.stream().collect(Collectors.toMap(TeacherDefaultMusicGroupSalary::getUserId, teacherDefaultMusicGroupSalary -> teacherDefaultMusicGroupSalary));

                TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalaryWithTeacherId = teacherDefaultMusicGroupSalariesGroupByTeacherId.get(courseScheduleTeacherSalary.getUserId());

                //如果结算方式是教师默认课酬
                if (settlementType.equals(SalarySettlementTypeEnum.TEACHER_DEFAULT.getCode())) {
                    //课程时长与结算单位时长占比
                    BigDecimal classTimeDuty = new BigDecimal(duration);
                    if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.HIGH)) {
                        classTimeDuty = classTimeDuty.divide(new BigDecimal(45), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    } else if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.CLASSROOM)) {
                        classTimeDuty = classTimeDuty.divide(new BigDecimal(40), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    } else {
                        classTimeDuty = classTimeDuty.divide(new BigDecimal(30), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    }
                    BigDecimal teacherDefaultSalary = new BigDecimal(0);
                    if(Objects.nonNull(teacherDefaultMusicGroupSalaryWithTeacherId)){
                        teacherDefaultSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalaryWithTeacherId.getMainTeacher30MinSalary() : teacherDefaultMusicGroupSalaryWithTeacherId.getAssistantTeacher30MinSalary();
                    }
                    teacherSalary = teacherDefaultSalary.multiply(classTimeDuty).setScale(2, BigDecimal.ROUND_HALF_UP);
                } else if (settlementType.equals(SalarySettlementTypeEnum.GRADIENT_SALARY.getCode())) {
                    //课程时长与结算单位时长占比
                    BigDecimal classTimeDuty = new BigDecimal(duration);
                    if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.HIGH)) {
                        classTimeDuty = classTimeDuty.divide(new BigDecimal(45), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    } else if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.CLASSROOM)) {
                        classTimeDuty = classTimeDuty.divide(new BigDecimal(40), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    } else {
                        classTimeDuty = classTimeDuty.divide(new BigDecimal(90), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    }
                    BigDecimal teacherDefaultSalary = new BigDecimal(0);
                    if(Objects.nonNull(teacherDefaultMusicGroupSalaryWithTeacherId)){
                        teacherDefaultSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalaryWithTeacherId.getMainTeacher90MinSalary() : teacherDefaultMusicGroupSalaryWithTeacherId.getAssistantTeacher90MinSalary();
                    }
                    teacherSalary = teacherDefaultSalary.multiply(classTimeDuty).setScale(2, BigDecimal.ROUND_HALF_UP);
                }
            }else{
                teacherSalary=courseScheduleTeacherSalary.getExpectSalary();
            }

            BigDecimal subsidy = courseSubsidyMap.get(courseSchedule.getSchoolId());
            if (Objects.isNull(subsidy)) {
                subsidy = new BigDecimal(0);
            }
            teacherSalary = teacherSalary.add(subsidy);
            //更新教师结算信息
            courseScheduleTeacherSalary.setActualSalary(teacherSalary);
            courseScheduleTeacherSalary.setSettlementTime(now);
            courseScheduleTeacherSalaryDao.update(courseScheduleTeacherSalary);

            //生成教师账户资金变动记录
            sysUserCashAccountService.updateBalance(courseScheduleTeacherSalary.getUserId(), teacherSalary);
            SysUserCashAccount teacherCashAccount = sysUserCashAccountService.get(courseScheduleTeacherSalary.getUserId().intValue());
            SysUserCashAccountDetail teacherCashAccountDetail = new SysUserCashAccountDetail();
            teacherCashAccountDetail.setUserId(courseScheduleTeacherSalary.getUserId());
            teacherCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.WAGE);
            teacherCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
            teacherCashAccountDetail.setAmount(teacherSalary);
            teacherCashAccountDetail.setBalance(teacherCashAccount.getBalance());
            teacherCashAccountDetail.setAttribute(courseScheduleTeacherSalary.getCourseScheduleId().toString());
            userCashAccountDetails.add(teacherCashAccountDetail);

        });
        sysUserCashAccountDetailDao.batchInsert(userCashAccountDetails);
    }

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

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateVipGroupCourseTeacherSalary(Integer vipGroupId, Integer studentChangeNum, VipGroupStatusEnum vipGroupStatusEnum) {
        VipGroup vipGroup = vipGroupService.get(vipGroupId.longValue());
        if(Objects.isNull(vipGroupStatusEnum)){
            vipGroupStatusEnum=vipGroup.getStatus();
        }
        Integer studentNum = classGroupStudentMapperDao.countGroupStudentNum(vipGroupId.toString(), GroupType.VIP.getCode());
        Integer oldStudentNum = studentNum-studentChangeNum;
        if(oldStudentNum<0){
            oldStudentNum=0;
        }
        ClassGroupTeacherSalary classGroupTeacherSalary = classGroupTeacherSalaryDao.findByVipGoupAndTeacher(vipGroupId, vipGroup.getUserId());
        BigDecimal onlineTeacherSalary,
                offlineTeacherSalary;
        if((oldStudentNum==0&&!vipGroupStatusEnum.equals(VipGroupStatusEnum.APPLYING))
                ||Objects.isNull(classGroupTeacherSalary)){
            TeacherDefaultVipGroupSalary teacherDefaultVipGroupSalary = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(vipGroup.getUserId(),
                    vipGroup.getVipGroupCategoryId());
            if(Objects.isNull(teacherDefaultVipGroupSalary)){
                throw new BizException("请设置课酬");
            }
            onlineTeacherSalary=teacherDefaultVipGroupSalary.getOnlineClassesSalary();
            offlineTeacherSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary();
        }else{
            onlineTeacherSalary=classGroupTeacherSalary.getOnlineClassesSalary();
            offlineTeacherSalary=classGroupTeacherSalary.getSalary();
        }

        if(oldStudentNum==0){
            VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroup.getVipGroupCategoryId().intValue());
            oldStudentNum = vipGroupCategory.getStudentNum();
        }

        if(Objects.isNull(classGroupTeacherSalary)){
            ClassGroup classGroup = classGroupDao.findByMusicGroupAndType(vipGroupId.toString(), GroupType.VIP.getCode());
            classGroupTeacherSalary=new ClassGroupTeacherSalary();
            classGroupTeacherSalary.setGroupType(GroupType.VIP);
            classGroupTeacherSalary.setMusicGroupId(vipGroupId.toString());
            classGroupTeacherSalary.setClassGroupId(classGroup.getId());
            classGroupTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
            classGroupTeacherSalary.setUserId(vipGroup.getUserId());
            classGroupTeacherSalaryDao.insert(classGroupTeacherSalary);
        }

        BigDecimal studentNumDecimal = new BigDecimal(studentNum);
        BigDecimal oldStudentNumDecimal = new BigDecimal(oldStudentNum);

        if(Objects.nonNull(onlineTeacherSalary)){
            onlineTeacherSalary = onlineTeacherSalary
                    .divide(oldStudentNumDecimal, CommonConstants.DECIMAL_PLACE,BigDecimal.ROUND_DOWN)
                    .multiply(studentNumDecimal).setScale(0, BigDecimal.ROUND_HALF_UP);
        }
        if(Objects.nonNull(offlineTeacherSalary)){
            offlineTeacherSalary = offlineTeacherSalary
                    .divide(oldStudentNumDecimal,CommonConstants.DECIMAL_PLACE,BigDecimal.ROUND_DOWN)
                    .multiply(studentNumDecimal).setScale(0,BigDecimal.ROUND_HALF_UP);
        }

        classGroupTeacherSalary.setOnlineClassesSalary(onlineTeacherSalary);
        classGroupTeacherSalary.setSalary(offlineTeacherSalary);

        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByGroupWithNotStart(vipGroupId.toString(), GroupType.VIP.getCode());
        if(!CollectionUtils.isEmpty(courseScheduleTeacherSalaries)){
            List<Long> courseIds = courseScheduleTeacherSalaries.stream().map(CourseScheduleTeacherSalary::getCourseScheduleId).collect(Collectors.toList());
            List<Map<Integer, String>> teachModeById = courseScheduleDao.getTeachModeById(courseIds);
            Map<Integer, String> coureTeachModeMap = MapUtil.convertIntegerMap(teachModeById);
            for(int i=0;i<courseScheduleTeacherSalaries.size();i++){
                String courseType = coureTeachModeMap.get(courseScheduleTeacherSalaries.get(i).getCourseScheduleId());
                if(courseType.equals(TeachModeEnum.ONLINE.getCode())){
                    courseScheduleTeacherSalaries.get(i).setExpectSalary(onlineTeacherSalary);
                }else if(courseType.equals(TeachModeEnum.OFFLINE.getCode())){
                    courseScheduleTeacherSalaries.get(i).setExpectSalary(offlineTeacherSalary);
                }
            }
            courseScheduleTeacherSalaryDao.batchUpdateTeacherExpectSalarys(courseScheduleTeacherSalaries);
        }
        classGroupTeacherSalaryDao.update(classGroupTeacherSalary);
    }
}
