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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.*;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.dal.page.CourseSalaryQueryInfo4Web;
import com.ym.mec.biz.dal.page.CourseScheduleTeacherSalaryQueryInfo;
import com.ym.mec.biz.dal.page.ExportTeacherSalaryQueryInfo;
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.thirdparty.message.MessageSenderPluginContext;
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.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
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
    @Lazy
    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 CourseScheduleRewardsRulesService courseScheduleRewardsRulesService;
    @Autowired
    private VipGroupCategoryDao vipGroupCategoryDao;
    @Autowired
    private StudentAttendanceDao studentAttendanceDao;
    @Autowired
    private TeacherSalaryComplaintsDao teacherSalaryComplaintsDao;
    @Autowired
    private TeacherCourseRewardService teacherCourseRewardService;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private TeacherCourseRewardDao teacherCourseRewardDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private TeacherDefaultPracticeGroupSalaryDao teacherDefaultPracticeGroupSalaryDao;

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

    //按节数计算课酬的课程类型
    protected static final Set<CourseSchedule.CourseScheduleType> UNIT_PRICE_COURSE_TYPES=new HashSet<>(Arrays.asList(CourseSchedule.CourseScheduleType.HIGH_ONLINE, CourseSchedule.CourseScheduleType.MUSIC_NETWORK));

    @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 practiceTeacherSalarySettlement() {
//        int days = Integer.parseInt(sysConfigDao.findByParamName(SysConfigService.VIP_APPEAL_DAYS_RANGE).getParanValue());
//        int days = 0;
        //获取教师未结算课程记录
        Date now = new Date();
        Date date = DateUtil.addMonths(now, -1);
        String startDate = DateUtil.format(DateUtil.getFirstDayOfMonth(date),DateUtil.DEFAULT_PATTERN);
        String endDate = DateUtil.format(DateUtil.getLastDayOfMonth(date),DateUtil.DEFAULT_PATTERN);
        List<CourseScheduleTeacherSalary> someDayAgoTeacherCourseSalaryNoSettlement = courseScheduleTeacherSalaryDao.findTeacherCourseSalaryNoSettlement(startDate,endDate);
        if (!CollectionUtils.isEmpty(someDayAgoTeacherCourseSalaryNoSettlement)) {
            someDayAgoTeacherCourseSalaryNoSettlement.forEach(courseScheduleTeacherSalary -> {
                courseScheduleTeacherSalary.setActualSalary(courseScheduleTeacherSalary.getTeacherActualSalary());
                courseScheduleTeacherSalary.setSettlementTime(now);
                courseScheduleTeacherSalaryDao.update(courseScheduleTeacherSalary);
            });
        }
        //获取未转结的
        List<TeacherCourseReward> teacherCourseRewards = teacherCourseRewardService.findBySettlementStatus(0);
        if(teacherCourseRewards.size() > 0){
            //逗号分隔的课程拆分
            List<String> collect = teacherCourseRewards.stream().map(e -> e.getCourseScheduleIdList()).collect(Collectors.toList());
            List<Long> courseScheduleIds = new ArrayList<>();
            collect.forEach(e->{
                if(!StringUtils.isEmpty(e)){
                    String[] split = e.split(",");
                    for (String s : split) {
                        courseScheduleIds.add(Long.parseLong(s));
                    }
                }
            });
            if (courseScheduleIds.size() > 0){
                //去掉有未结束课程的数据
                List<Long> mapList = courseScheduleDao.findNotStartCourseByIds(courseScheduleIds);
                List<TeacherAttendance> teacherAttendances = teacherAttendanceDao.findTeacherIdByCourseSchedule(courseScheduleIds);
                Map<Long, TeacherAttendance> teacherAttendancesMap = teacherAttendances.stream().collect(Collectors.toMap(TeacherAttendance::getCourseScheduleId,t -> t));
                String courseScheduleIdList = null;
                StringBuffer memo;
                BigDecimal multiply;
                BigDecimal add;
                outer1:for (TeacherCourseReward e : teacherCourseRewards) {
                    memo = new StringBuffer();
                    courseScheduleIdList = e.getCourseScheduleIdList();
                    if(!StringUtils.isEmpty(courseScheduleIdList)){
                        String[] split = courseScheduleIdList.split(",");
                        for (String s : split) {
                            //如果包含未结算的课程，不转结
                            if(mapList.contains(Long.parseLong(s))){
                                continue outer1;
                            }
                        }
                        //转结,是否正常签到，签退
                        BigDecimal expectRewardAmount = e.getExpectRewardAmount().divide(new BigDecimal(split.length));
                        multiply = expectRewardAmount.multiply(new BigDecimal(0.5));
                        add = expectRewardAmount.multiply(new BigDecimal(0));
                        for (String s : split) {
                            //如果包含未结算的课程，不转结
                            TeacherAttendance teacherAttendance = teacherAttendancesMap.get(Long.parseLong(s));
                            if(teacherAttendance == null){
                                throw new BizException("教师签到记录不存在 : courseScheduleId:{}",s);
                            }
                            if(teacherAttendance.getSignInStatus() == null || teacherAttendance.getSignInStatus() == YesOrNoEnum.NO){
                                expectRewardAmount = expectRewardAmount.subtract(multiply);
                                memo.append("课程").append(s).append("异常签到;");
                            }
                            if(teacherAttendance.getSignOutStatus() == null || teacherAttendance.getSignOutStatus() == YesOrNoEnum.NO){
                                expectRewardAmount = expectRewardAmount.subtract(multiply);
                                memo.append("课程").append(s).append("异常签退;");
                            }
                            add = add.add(expectRewardAmount);
                            expectRewardAmount = e.getExpectRewardAmount().divide(new BigDecimal(split.length));
                        }
                        e.setMemo(memo.toString());
                        e.setActualRewardAmount(add);
                        e.setSettlementStatus(YesOrNoEnum.YES);
                        e.setSettlementDate(now);
                    }
                }
                teacherCourseRewardService.batchUpdate(teacherCourseRewards);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void teacherSalarySettlement() {
//        int days = Integer.parseInt(sysConfigDao.findByParamName(SysConfigService.VIP_APPEAL_DAYS_RANGE).getParanValue());
//        int days = 0;
        BigDecimal percent = new BigDecimal(10);
        Date now = new Date();
        Date date = DateUtil.addMonths(now, -1);
        String startDate = DateUtil.format(DateUtil.getFirstDayOfMonth(date),DateUtil.DEFAULT_PATTERN);
        String endDate = DateUtil.format(DateUtil.getLastDayOfMonth(date),DateUtil.DEFAULT_PATTERN);
        //获取教师未结算课程记录
        List<CourseScheduleTeacherSalary> someDayAgoTeacherCourseSalaryNoSettlement = courseScheduleTeacherSalaryDao.findSomeDayAgoTeacherCourseSalaryNoSettlement(startDate,endDate);
        if (CollectionUtils.isEmpty(someDayAgoTeacherCourseSalaryNoSettlement)) {
            LOGGER.info("未获取到未结算课酬记录!");
            return;
        }

        vipGroupService.updateHistoryTeacherSalaryOfOnline(startDate, endDate);
        //获取未结算课程编号列表
        List<Long> courseScheduleIds = someDayAgoTeacherCourseSalaryNoSettlement.stream().map(CourseScheduleTeacherSalary::getCourseScheduleId).collect(Collectors.toList());

        //所有课程的学生考勤记录
//        List<StudentAttendance> studentAttendances = studentAttendanceDao.findByCourseIds(courseScheduleIds);
//        Map<Long, List<StudentAttendance>> courseStudentAttendancesMap = studentAttendances.stream().collect(Collectors.groupingBy(StudentAttendance::getCourseScheduleId));

        //所有课程的教师考勤记录
//        List<TeacherAttendance> teacherAttendancesByCourseSchedule = teacherAttendanceDao.findTeacherIdByCourseSchedule(courseScheduleIds);
//        Map<Long, List<TeacherAttendance>> courseTeacherAttendancesMap = teacherAttendancesByCourseSchedule.stream().collect(Collectors.groupingBy(TeacherAttendance::getCourseScheduleId));

        //获取未结算课程投诉记录
        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;
            }

//            List<StudentAttendance> courseStudentAttendances = courseStudentAttendancesMap.get(courseScheduleTeacherSalary.getCourseScheduleId());
//            int normalStudentNum=0;
//            if(CollectionUtils.isEmpty(courseStudentAttendances)){
//                return;
//            }
//            for (StudentAttendance courseStudentAttendance : courseStudentAttendances) {
//                if(Objects.nonNull(courseStudentAttendance.getStatus())&&courseStudentAttendance.getStatus().equals(StudentAttendanceStatusEnum.NORMAL)){
//                    normalStudentNum+=1;
//                }
//            }
//            if(normalStudentNum==0){
//                return;
//            }

//            List<TeacherAttendance> teacherAttendances = courseTeacherAttendancesMap.get(courseScheduleTeacherSalary.getCourseScheduleId());
//            if(CollectionUtils.isEmpty(teacherAttendances)){
//                return;
//            }
//            int teacherAttendanceNum=0;
//            for (TeacherAttendance teacherAttendance : teacherAttendances) {
//                if(Objects.nonNull(teacherAttendance.getSignInTime())||Objects.nonNull(teacherAttendance.getSignOutTime())){
//                    teacherAttendanceNum+=1;
//                }
//            }
//            if(teacherAttendanceNum==0){
//                return;
//            }

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

            //教师预计课酬
            BigDecimal expectSalary = courseScheduleTeacherSalary.getTeacherActualSalary();
            //当前课程每个学生平均课酬
//            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.setActualSalary(expectSalary);
            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 date = DateUtil.addMonths(now, -1);
        String startDate = DateUtil.format(DateUtil.getFirstDayOfMonth(date),DateUtil.DEFAULT_PATTERN);
        String endDate = DateUtil.format(DateUtil.getLastDayOfMonth(date),DateUtil.DEFAULT_PATTERN);
        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(startDate,endDate);
        //课程编号列表
        List<Long> courseScheduleIds = yesterdayCourseSchedules.stream().map(CourseSchedule::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(courseScheduleIds)) {
            return;
        }

        //获取课程对应教学点补贴
        List<Map<Long, 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<TeacherAttendance> allTeacherAttendances = teacherAttendanceDao.findByCourseSchedules(courseScheduleIds);
        Map<String, List<TeacherAttendance>> teacherCourseAttendanceMap = allTeacherAttendances.stream().collect(Collectors.groupingBy(ta -> org.apache.commons.lang3.StringUtils.joinWith(":", ta.getCourseScheduleId(), ta.getTeacherId())));

        //学员点名记录
        List<StudentAttendance> allStudentAttendances = studentAttendanceDao.findByCourseIds(courseScheduleIds);
        Map<Long, List<StudentAttendance>> courseStudentAttendanceMap = allStudentAttendances.stream().collect(Collectors.groupingBy(StudentAttendance::getCourseScheduleId));

        //需要根据实际上课学员结算课酬的课程编号
        List<Long> needStudentAttendanceCourseScheduleIds = yesterdayCourseSchedules.stream()
                .filter(c -> CourseSchedule.CourseScheduleType.HIGH_ONLINE.equals(c.getType())
                        || CourseSchedule.CourseScheduleType.MUSIC_NETWORK.equals(c.getType())
                        || CourseSchedule.CourseScheduleType.HIGH.equals(c.getType()))
                .map(CourseSchedule::getId).collect(Collectors.toList());

        List<StudentAttendance> studentAttendances = studentAttendanceDao.findByCourseIds(needStudentAttendanceCourseScheduleIds);
        Map<Long, Long> courseNormalStudentsMap = new HashMap<>();
        if(!CollectionUtils.isEmpty(studentAttendances)){
            courseNormalStudentsMap =studentAttendances.stream()
                    .filter(studentAttendance -> StudentAttendanceStatusEnum.NORMAL.equals(studentAttendance.getStatus()))
                    .collect(Collectors.groupingBy(StudentAttendance::getCourseScheduleId, Collectors.counting()));
        }

        //课程对应乐团结算方式集合
        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);
        });
        //计算课酬
        for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
            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;
                }
            }

            if(CourseSchedule.CourseScheduleType.HIGH.equals(courseSchedule.getType())){
                courseSchedule.setType(CourseSchedule.CourseScheduleType.HIGH_ONLINE);
            }

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

            if(CourseSchedule.CourseScheduleType.MUSIC_NETWORK.equals(courseSchedule.getType())||CourseSchedule.CourseScheduleType.HIGH_ONLINE.equals(courseSchedule.getType())){
                //根据课程类型获取对应的默认课酬设置列表
                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());

                Long normalStudentNum = courseNormalStudentsMap.get(courseSchedule.getId());
                if(Objects.isNull(normalStudentNum)){
                    normalStudentNum = Long.valueOf(0);
                }
                if(normalStudentNum>5){
                    normalStudentNum=Long.valueOf(5);
                }
                if(Objects.nonNull(teacherDefaultMusicGroupSalaryWithTeacherId)&& org.apache.commons.lang3.StringUtils.isNoneBlank(teacherDefaultMusicGroupSalaryWithTeacherId.getSalaryRuleJson())){
                    JSONObject salaryRuleJsonObject = JSONObject.parseObject(teacherDefaultMusicGroupSalaryWithTeacherId.getSalaryRuleJson());
                    teacherSalary = salaryRuleJsonObject.getBigDecimal(normalStudentNum.toString());
                }
                if(Objects.isNull(teacherSalary)){
                    teacherSalary = BigDecimal.ZERO;
                }
            }else if(durationIsChange&&!UNIT_PRICE_COURSE_TYPES.contains(courseSchedule.getType())){
                //根据课程类型获取对应的默认课酬设置列表
                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());

                //课程时长与结算单位时长占比
                BigDecimal classTimeDuty = new BigDecimal(duration);
                BigDecimal teacherDefaultSalary = new BigDecimal(0);

                //如果结算方式是教师默认课酬
                if (settlementType.equals(SalarySettlementTypeEnum.TEACHER_DEFAULT.getCode())) {
                    classTimeDuty = classTimeDuty.divide(new BigDecimal(30), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    if(Objects.nonNull(teacherDefaultMusicGroupSalaryWithTeacherId)){
                        teacherDefaultSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalaryWithTeacherId.getMainTeacher30MinSalary() : teacherDefaultMusicGroupSalaryWithTeacherId.getAssistantTeacher30MinSalary();
                    }
                } else if (settlementType.equals(SalarySettlementTypeEnum.GRADIENT_SALARY.getCode())) {
                    classTimeDuty = classTimeDuty.divide(new BigDecimal(90), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                    if(Objects.nonNull(teacherDefaultMusicGroupSalaryWithTeacherId)){
                        teacherDefaultSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalaryWithTeacherId.getMainTeacher90MinSalary() : teacherDefaultMusicGroupSalaryWithTeacherId.getAssistantTeacher90MinSalary();
                    }
                }

                if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.HIGH)) {
                    classTimeDuty = new BigDecimal(duration).divide(new BigDecimal(45), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                } else if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.CLASSROOM)) {
                    teacherDefaultSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalaryWithTeacherId.getMainTeacher30MinSalary() : teacherDefaultMusicGroupSalaryWithTeacherId.getAssistantTeacher30MinSalary();
                    classTimeDuty = new BigDecimal(duration).divide(new BigDecimal(40), BigDecimal.ZERO.intValue(), BigDecimal.ROUND_DOWN);
                }

                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);

            //扣除费用
            BigDecimal deductCost = BigDecimal.ZERO;
            List<TeacherAttendance> courseTeacherAttendances = teacherCourseAttendanceMap.get(org.apache.commons.lang3.StringUtils.joinWith(":", courseScheduleTeacherSalary.getCourseScheduleId(), courseScheduleTeacherSalary.getUserId()));

            boolean isCallName = false;
            List<StudentAttendance> courseStudentAttendance = courseStudentAttendanceMap.get(courseScheduleTeacherSalary.getCourseScheduleId());
            if(!CollectionUtils.isEmpty(courseStudentAttendance)){
                long csaNum = courseStudentAttendance.stream().filter(csa -> DateUtil.hoursBetween(csa.getCreateTime(), courseSchedule.getStartClassTime()) < 4).count();
                if(csaNum>0){
                    isCallName = true;
                }
            }

            if(CollectionUtils.isEmpty(courseTeacherAttendances)){
                //无签到记录扣除全部课酬
                deductCost = deductCost.add(teacherSalary);
            }else{
                TeacherAttendance teacherAttendance = courseTeacherAttendances.get(0);
                if(Objects.isNull(teacherAttendance.getSignInStatus())){
                    //未签到扣除全部课酬
                    deductCost = deductCost.add(teacherSalary);
                }else if(YesOrNoEnum.NO.equals(teacherAttendance.getSignInStatus())){
                    int signCourseTimeBetween = DateUtil.minutesBetween(teacherAttendance.getSignInTime(), courseSchedule.getStartClassTime());
                    if(signCourseTimeBetween>=0&&signCourseTimeBetween<20){
                        //未提前20分钟打卡扣除50元
                        deductCost = deductCost.add(new BigDecimal(50));
                    }else if(signCourseTimeBetween<0&&signCourseTimeBetween>-30){
                        //迟到30分钟内扣除一半课酬
                        deductCost = deductCost.add(teacherSalary.divide(new BigDecimal(2)));
                    }else if(signCourseTimeBetween<=-30){
                        //迟到30分钟及以上扣除全部课酬
                        deductCost = deductCost.add(teacherSalary);
                    }
                }

                if(!isCallName){
                    //未点名扣除一半课酬
                    deductCost = deductCost.add(teacherSalary.divide(new BigDecimal(2)));
                }else if((Objects.isNull(teacherAttendance.getSignOutStatus())||YesOrNoEnum.NO.equals(teacherAttendance.getSignOutStatus()))&&isCallName){
                    //异常签退或者未签退，但是正常点名扣除50元课酬
                    deductCost = deductCost.add(new BigDecimal(50));
                }


            }

            BigDecimal finalSalary = teacherSalary.subtract(deductCost);

            //更新教师结算信息
            courseScheduleTeacherSalary.setActualSalary(finalSalary.compareTo(BigDecimal.ZERO)<0?BigDecimal.ZERO:finalSalary);
            courseScheduleTeacherSalary.setSettlementTime(now);
            courseScheduleTeacherSalaryDao.update(courseScheduleTeacherSalary);
        }
    }

    @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(queryInfo.getIsExport() && count > 50000){
            throw new BizException("数据集太大，不能导出.最大数据集不能超过50000");
        }
        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, isolation = Isolation.READ_COMMITTED)
    public void updateVipGroupCourseTeacherSalary(Integer vipGroupId, Integer oldTeacherId) {
        VipGroup vipGroup = vipGroupService.get(vipGroupId.longValue());

        BigDecimal onlineTeacherSalary=BigDecimal.ZERO,
                offlineTeacherSalary=BigDecimal.ZERO;

        Map<String, BigDecimal> salary = vipGroupService.countVipGroupPredictFee(vipGroup, vipGroup.getUserId(), null, null);

        if(Objects.nonNull(salary)){
            onlineTeacherSalary=salary.get("onlineTeacherSalary");
            offlineTeacherSalary=salary.get("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);
        }
    }

    @Override
    public List<ExportTeacherSalaryDto> exportTeacherSalary(ExportTeacherSalaryQueryInfo queryInfo) {
        //4月份之后的需要扣异常考勤的课酬
        //扣除有异常考勤的课酬
        Map<String, Object> params = new HashMap<>();
        MapUtil.populateMap(params, queryInfo);
        String firstDayOfMonth = DateUtil.format(DateUtil.getFirstDayOfMonth(queryInfo.getDate()),DateUtil.ISO_EXPANDED_DATE_FORMAT);
        String lastDayOfMonth =  DateUtil.format(DateUtil.getLastDayOfMonth(queryInfo.getDate()),DateUtil.ISO_EXPANDED_DATE_FORMAT);
        params.put("firstDayOfMonth",firstDayOfMonth);
        params.put("lastDayOfMonth",lastDayOfMonth);
        List<ExportTeacherSalaryDto> exportTeacherSalaryDtos = new ArrayList<>();
        //乐团课
        exportTeacherSalaryDtos.addAll(courseScheduleTeacherSalaryDao.exportMusicTeacherSalary(params));
        //vip课
        List<ExportTeacherSalaryDto> exportVipTeacherSalaryDtos = courseScheduleTeacherSalaryDao.exportVipTeacherSalary(params);
        //获取有奖励的vip课  .collect(Collectors.toMap(Group::getId, group -> group));
        List<TaskRewardsRulesDto> rewardsRulesDtos = courseScheduleRewardsRulesService.queryVipGroupTeacherClassTimesByMonth(firstDayOfMonth,lastDayOfMonth);
        Map<Integer,Double> rewardMap = new HashMap<>(1000);
        Map<Integer,String> rewardNameMap = new HashMap<>(1000);
        if(rewardsRulesDtos != null && rewardsRulesDtos.size() > 0){
            List<Integer> activeIds = rewardsRulesDtos.stream().map(e -> e.getActiveId()).collect(Collectors.toList());
            List<CourseScheduleRewardsRules> rewardsRules = courseScheduleRewardsRulesService.findByIds(activeIds);
            Map<Integer, List<CourseScheduleRewardsRules>> integerListMap = rewardsRules.stream().collect(Collectors.groupingBy(CourseScheduleRewardsRules::getId));
            rewardsRulesDtos.forEach(e->{
                CourseScheduleRewardsRules rewardsRule = integerListMap.get(e.getActiveId()).get(0);
                List<RewardsRulesJsonDto> rulesJsonDtos = JSONObject.parseArray(rewardsRule.getRewardsRulesJson(), RewardsRulesJsonDto.class);
                BigDecimal money = BigDecimal.ZERO;
                //STAIR 阶梯, PER 累计, TOTAL
                RewardsRulesJsonDto dto;
                int times = e.getTimes();
                switch (rewardsRule.getRewardMode()) {
                    case STAIR:
                        for (int i = 0;i< rulesJsonDtos.size();i++){
                            dto = rulesJsonDtos.get(i);
                            if (e.getTimes() >= dto.getMin()) {
                                //最后一个梯度
                                if(rulesJsonDtos.size()-1 == i){
                                    money = money.add(dto.getMoney().multiply(new BigDecimal(times)));
                                }else if(e.getTimes() >= dto.getMax()){
                                    times = Math.abs(dto.getMax() - times);
                                    money = money.add(dto.getMoney().multiply(new BigDecimal(dto.getMax()-dto.getMin()+1)));
                                }else {
                                    money = money.add(dto.getMoney().multiply(new BigDecimal(times)));
                                }
                            }
                        }
                        break;
                    case PER:
                        for (int i = 0;i< rulesJsonDtos.size();i++){
                            dto = rulesJsonDtos.get(i);
                            if (e.getTimes() >= dto.getMin()) {
                                money = dto.getMoney().multiply(new BigDecimal(times));
                            }
                        }
                        break;
                    case TOTAL:
                        break;
                }
                if (money.doubleValue() > 0) {
                    String[] split = e.getCourseScheduleIds().split(",");
                    switch (rewardsRule.getRewardMode()) {
                        case STAIR:
                            List<String> list = new ArrayList(Arrays.asList(split));
                            Collections.sort(list);
                            int fromIndex = 0;
                            List<String> subList;
                            int max = 0;
                            for (RewardsRulesJsonDto rulesJsonDto:rulesJsonDtos) {
                                if(list.size() < fromIndex){
                                    break;
                                }
                                max = rulesJsonDto.getMax();
                                if(list.size() < rulesJsonDto.getMax()){
                                    max = list.size();
                                }
                                subList = list.subList(fromIndex,max);
                                fromIndex = rulesJsonDto.getMax();
                                if(subList != null && subList.size() > 0){
                                    subList.forEach(courseId->{
                                        rewardMap.put(Integer.parseInt(courseId),rulesJsonDto.getMoney().doubleValue());
                                        rewardNameMap.put(Integer.parseInt(courseId),e.getActiveName());
                                    });
                                }
                            }
                            break;
                        case PER:
                            for (int i = 0; i < split.length; i++) {
                                rewardMap.put(Integer.parseInt(split[i]),money.doubleValue()/split.length);
                                rewardNameMap.put(Integer.parseInt(split[i]),e.getActiveName());
                            }
                            break;
                    }
                }
            });
        }
        exportVipTeacherSalaryDtos.forEach(e->{
            e.setRewards(rewardMap.get(e.getCourseScheduleId()));
            e.setActiveName(rewardNameMap.get(e.getCourseScheduleId()));
        });
        exportTeacherSalaryDtos.addAll(exportVipTeacherSalaryDtos);
        //vip课（梯度课酬）
        //陪练课
        exportTeacherSalaryDtos.addAll(courseScheduleTeacherSalaryDao.exportPracticeTeacherSalary(params));
        exportTeacherSalaryDtos.sort(Comparator.comparing(ExportTeacherSalaryDto::getTeacherId));
        return exportTeacherSalaryDtos;
    }


    @Override
    public List<Long> querySettlementScheduleId(String courseScheduleIds) {
        return courseScheduleTeacherSalaryDao.querySettlementScheduleId(courseScheduleIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmTeacherMonthSalary(Integer teacherId, String month) {
        if(Objects.isNull(month)){
            month=DateUtil.dateToString(DateUtil.addMonths(new Date(), -1), "yyyy-MM");
        }
        List<Long> teacherSalaryIds = courseScheduleTeacherSalaryDao.findTeacherSalaryIdsWithMonth(teacherId, month);
        if(CollectionUtils.isEmpty(teacherSalaryIds)){
            return;
        }
        courseScheduleTeacherSalaryDao.updateTeacherSalaryConfirmStatus(teacherSalaryIds,TeacherSalaryConfirmStatus.CONFIRMED);
        teacherCourseRewardDao.updateTeacherRewardConfirmStatusWithMonth(month, teacherId, TeacherSalaryConfirmStatus.CONFIRMED);
    }

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

        List<TeacherCourseSalaryDetail4WebDto> dataList = null;
        int count = courseScheduleTeacherSalaryDao.countIsSettlementCourseSalarys(params);
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = courseScheduleTeacherSalaryDao.findIsSettlementCourseSalarys(params);
            List<Long> courseScheduleIds = dataList.stream().map(TeacherCourseSalaryDetail4WebDto::getCourseScheduleId).collect(Collectors.toList());
            List<Map<Long, BigDecimal>> coursePaymentMaps = courseScheduleStudentPaymentDao.findCoursePayment(courseScheduleIds);
            Map<Long, BigDecimal> coursePaymentMap = MapUtil.convertIntegerMap(coursePaymentMaps);
            for (TeacherCourseSalaryDetail4WebDto teacherCourseSalaryDetail4WebDto : dataList) {
                if(Objects.nonNull(teacherCourseSalaryDetail4WebDto.getReduceSalary())){
                    teacherCourseSalaryDetail4WebDto.setFinalSalary(teacherCourseSalaryDetail4WebDto.getActualSalary().subtract(teacherCourseSalaryDetail4WebDto.getReduceSalary()));
                }else{
                    teacherCourseSalaryDetail4WebDto.setFinalSalary(teacherCourseSalaryDetail4WebDto.getActualSalary());
                }
                BigDecimal paymentPrice = coursePaymentMap.get(teacherCourseSalaryDetail4WebDto.getCourseScheduleId());
                teacherCourseSalaryDetail4WebDto.setActualReceipts(paymentPrice);
            }
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    public Map<String, Object> findTeacherSettlementCourseSalarys(CourseSalaryQueryInfo4Web queryInfo4Web) {
        if(Objects.isNull(queryInfo4Web.getMonth())){
            queryInfo4Web.setMonth(DateUtil.dateToString(DateUtil.addMonths(new Date(), -1), "yyyy-MM"));
        }
        PageInfo<TeacherCourseSalaryDetail4WebDto> pageInfo = findIsSettlementCourseSalarys(queryInfo4Web);
        Map<String, Object> result=new HashMap<>();
        result.put("pageInfo",pageInfo);
        List<CourseTeacherSalaryStatisticsDto> teacherGroupTypeSalary = new ArrayList<>();
        if(queryInfo4Web.getPage()<=1){
            teacherGroupTypeSalary = courseScheduleTeacherSalaryDao.getTeacherGroupTypeSalary(queryInfo4Web.getMonth(), queryInfo4Web.getTeacherId());
            CourseTeacherSalaryStatisticsDto courseTeacherSalaryStatisticsDto = teacherCourseRewardDao.teacherCourseRewardStatWithMonth(queryInfo4Web.getTeacherId(), queryInfo4Web.getMonth());
            if(Objects.isNull(courseTeacherSalaryStatisticsDto)){
                courseTeacherSalaryStatisticsDto=new CourseTeacherSalaryStatisticsDto();
            }
            courseTeacherSalaryStatisticsDto.setStatType("REWARD");
            teacherGroupTypeSalary.add(courseTeacherSalaryStatisticsDto);
        }
        result.put("stat", teacherGroupTypeSalary);
        if(!CollectionUtils.isEmpty(pageInfo.getRows())){
            if(TeacherSalaryConfirmStatus.CONFIRMED.equals(pageInfo.getRows().get(0).getConfirmStatus())||
                    TeacherSalaryConfirmStatus.COMPLETED.equals(pageInfo.getRows().get(0).getConfirmStatus())){
                result.put("confirmStatus",1);
            }else{
                result.put("confirmStatus",0);
            }
        }else{
            result.put("confirmStatus",0);
        }
        List<TeacherSalaryComplaints> teacherSalaryComplaintsWithMonth = teacherSalaryComplaintsDao.findTeacherSalaryComplaintsWithMonth(queryInfo4Web.getTeacherId(), queryInfo4Web.getMonth(), TeacherSalaryComplaintsStatusEnum.PENDING);
        if(CollectionUtils.isEmpty(teacherSalaryComplaintsWithMonth)){
            result.put("haveComplaints",0);
        }else{
            result.put("haveComplaints",1);
        }
        return result;
    }

    @Override
    public Map<String, Object> findTeacherYearSalarys(Integer teacherId, String year) {
        if(Objects.isNull(year)){
            year=DateUtil.getYear(new Date());
        }
        List<CourseTeacherSalaryStatisticsDto> teacherMonthSalarys = courseScheduleTeacherSalaryDao.getTeacherMonthSalarys(teacherId, year);
        BigDecimal totalSalary = BigDecimal.ZERO;
        for (CourseTeacherSalaryStatisticsDto teacherMonthSalary : teacherMonthSalarys) {
            if(Objects.nonNull(teacherMonthSalary.getTotalReduceSalary())){
                teacherMonthSalary.setTotalActualSalary(teacherMonthSalary.getTotalActualSalary().subtract(teacherMonthSalary.getTotalReduceSalary()));
            }
            totalSalary = totalSalary.add(teacherMonthSalary.getTotalActualSalary());
        }
        Map<String, Object> result=new HashMap<>();
        result.put("monthSalarys", teacherMonthSalarys);
        result.put("totalSalary", totalSalary);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void openSalaryConfirm(String month) {
        if(Objects.isNull(month)){
            month=DateUtil.dateToString(DateUtil.addMonths(new Date(), -1), "yyyy-MM");
        }
        int i = courseScheduleTeacherSalaryDao.countOpenConfirmSalarysWithMonth(month,null);
        if(i<=0){
            throw new BizException("课酬确认已开启");
        }
        List<Long> teacherSalaryIds = courseScheduleTeacherSalaryDao.findTeacherSalaryIdsWithMonth(null, month);
        if(CollectionUtils.isEmpty(teacherSalaryIds)){
            return;
        }
        courseScheduleTeacherSalaryDao.updateTeacherSalaryConfirmStatus(teacherSalaryIds,TeacherSalaryConfirmStatus.UNCONFIRMED);
        teacherCourseRewardDao.updateTeacherRewardConfirmStatusWithMonth(month, null, TeacherSalaryConfirmStatus.UNCONFIRMED);
        String teacherBaseUrl = sysConfigDao.findByParamName(SysConfigService.TEACHER_BASE_URL).getParanValue();
        String notifyUrl="8?"+teacherBaseUrl+"/#/remuneration?month=" + month;
        String monthStr = DateUtil.dateToString(DateUtil.stringToDate(month, "yyyy-MM"),"M月");
        String expireDateStr = DateUtil.dateToString(DateUtil.addDays(new Date(), 2), "M月d号");
        List<Integer> teacherIds = courseScheduleTeacherSalaryDao.findIsSettlementTeacherIdsWithMonth(month);
        Map<Integer, String> userMap = teacherIds.stream().collect(Collectors.toMap(Integer::valueOf, id->String.valueOf(id)));
        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.TEACHER_SALARY_CONFIRM_PUSH,
                userMap, null, 0, notifyUrl, "TEACHER", monthStr, expireDateStr);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeSalaryConfirm(String month) {
        if(Objects.isNull(month)){
            month=DateUtil.dateToString(DateUtil.addMonths(new Date(), -1), "yyyy-MM");
        }
        List<Long> teacherSalaryIds = courseScheduleTeacherSalaryDao.findTeacherSalaryIdsWithMonth(null, month);
        if(CollectionUtils.isEmpty(teacherSalaryIds)){
            return;
        }
        courseScheduleTeacherSalaryDao.updateTeacherSalaryConfirmStatusToComplied(teacherSalaryIds);
        teacherSalaryComplaintsDao.updateComplaintStatusTuDoneWithMonth(month);
        teacherCourseRewardDao.updateTeacherRewardConfirmStatusWithMonth(month, null, TeacherSalaryConfirmStatus.COMPLETED);
    }

    @Override
    public List<CourseScheduleTeacherSalary> createTeacherCourseSalary(CourseSchedule courseSchedule, List<Integer> teacherIds) {
        if(Objects.isNull(courseSchedule.getType())){
            throw new BizException("请指定课程类型");
        }

        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = new ArrayList<>();
        Date now = new Date();
        for (Integer teacherId : teacherIds) {
            CourseScheduleTeacherSalary courseScheduleTeacherSalary = new CourseScheduleTeacherSalary();
            courseScheduleTeacherSalary.setGroupType(courseSchedule.getGroupType());
            courseScheduleTeacherSalary.setMusicGroupId(courseSchedule.getMusicGroupId());
            courseScheduleTeacherSalary.setCourseScheduleId(courseSchedule.getId());
            courseScheduleTeacherSalary.setClassGroupId(courseSchedule.getClassGroupId());
            if(teacherId.equals(courseSchedule.getActualTeacherId())){
                courseScheduleTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
            }else{
                courseScheduleTeacherSalary.setTeacherRole(TeachTypeEnum.TEACHING);
            }
            courseScheduleTeacherSalary.setUserId(teacherId);
            courseScheduleTeacherSalary.setCreateTime(now);
            courseScheduleTeacherSalary.setUpdateTime(now);
        }
        switch (courseSchedule.getGroupType()){
            case MUSIC:
                //生成乐团课课酬
                createMusicGroupCourseTeacherSalary(courseSchedule, courseScheduleTeacherSalaries);
                break;
            case VIP:
                //生成vip课课酬
                createVipGroupCourseTeacherSalary(courseSchedule, courseScheduleTeacherSalaries);
                break;
            case PRACTICE:
                //生成网管课课酬
                createPracticeGroupCourseTeacherSalary(courseSchedule, courseScheduleTeacherSalaries);
                break;
        }
        return courseScheduleTeacherSalaries;
    }

    /**
     * @describe 创建课程指定教师的课酬记录-乐团课
     * @author Joburgess
     * @date 2020.10.22
     * @param courseSchedule: 课程计划
     * @param courseScheduleTeacherSalaries: 教师课酬记录基本信息
     * @return java.util.List<com.ym.mec.biz.dal.entity.CourseScheduleTeacherSalary>
     */
    private void createMusicGroupCourseTeacherSalary(CourseSchedule courseSchedule, List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries) {
        MusicGroup musicGroup = musicGroupDao.get(courseSchedule.getMusicGroupId());

        List<Integer> teacherIds = courseScheduleTeacherSalaries.stream().map(CourseScheduleTeacherSalary::getUserId).collect(Collectors.toList());

        List<Teacher> teachers = teacherDao.findByTeacherIds(teacherIds);
        Map<Integer, Teacher> teacherMap = teachers.stream().collect(Collectors.toMap(Teacher::getId, teacher -> teacher));

        List<TeacherDefaultMusicGroupSalary> allTeacherDefaultMusicGroupSalary = teacherDefaultMusicGroupSalaryDao.findByTeacher(teacherIds);
        Map<Integer, List<TeacherDefaultMusicGroupSalary>> teacherSalaryMap = allTeacherDefaultMusicGroupSalary.stream().collect(Collectors.groupingBy(TeacherDefaultMusicGroupSalary::getUserId));

        Date entryDate = DateUtil.stringToDate(sysConfigDao.findByParamName(SysConfigService.TEACHER_ENTRY_DATE).getParanValue(), "yyyy-MM-dd");

        long classCourseDuration = DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime());

        for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
            List<TeacherDefaultMusicGroupSalary> teacherSalaryList = teacherSalaryMap.get(courseScheduleTeacherSalary.getUserId());

            BigDecimal salary;

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

            TeacherDefaultMusicGroupSalary teacherDefaultMusicGroupSalary = collect.get(courseSchedule.getType());

            Teacher teacher = teacherMap.get(courseScheduleTeacherSalary.getUserId());
            if (teacherDefaultMusicGroupSalary == null) {
                throw new BizException("请设置" + teacher.getRealName() + "老师的" + courseSchedule.getType().getMsg() + "课酬");
            }

            //对应基准课酬
            BigDecimal baseSalary = new BigDecimal(0), classTimeDuty = new BigDecimal(0);

            SalarySettlementTypeEnum settlementType = musicGroup.getSettlementType();
            if (Objects.nonNull(teacher.getEntryDate())
                    && (teacher.getEntryDate().after(entryDate) || teacher.getEntryDate().getTime() == entryDate.getTime())) {
                settlementType = SalarySettlementTypeEnum.GRADIENT_SALARY;
            }

            //基准课酬
            if (settlementType.equals(SalarySettlementTypeEnum.TEACHER_DEFAULT) && teacherDefaultMusicGroupSalary != null) {
                //课程时长与结算单位时长占比
                classTimeDuty = new BigDecimal(classCourseDuration).divide(new BigDecimal(30), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                baseSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalary.getMainTeacher30MinSalary() : teacherDefaultMusicGroupSalary.getAssistantTeacher30MinSalary();
            }
            //阶梯课酬
            if (settlementType.equals(SalarySettlementTypeEnum.GRADIENT_SALARY) && teacherDefaultMusicGroupSalary != null) {
                //课程时长与结算单位时长占比
                classTimeDuty = new BigDecimal(classCourseDuration).divide(new BigDecimal(90), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
                baseSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalary.getMainTeacher90MinSalary() : teacherDefaultMusicGroupSalary.getAssistantTeacher90MinSalary();
            }

            //课堂课课酬改为按分钟数计算，并且时长占比向下取整
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.CLASSROOM)){
                baseSalary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalary.getMainTeacher30MinSalary() : teacherDefaultMusicGroupSalary.getAssistantTeacher30MinSalary();
                classTimeDuty = new BigDecimal(classCourseDuration).divide(new BigDecimal(40), BigDecimal.ZERO.intValue(), BigDecimal.ROUND_DOWN);
            }

            salary = baseSalary.multiply(classTimeDuty).setScale(2, BigDecimal.ROUND_HALF_UP);

            //基础技能提高课
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.HIGH)) {
                salary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalary.getMainTeacher30MinSalary() : teacherDefaultMusicGroupSalary.getAssistantTeacher30MinSalary();
                if (settlementType.equals(SalarySettlementTypeEnum.GRADIENT_SALARY)) {
                    salary = courseScheduleTeacherSalary.getTeacherRole().equals(TeachTypeEnum.BISHOP) ? teacherDefaultMusicGroupSalary.getMainTeacher90MinSalary() : teacherDefaultMusicGroupSalary.getAssistantTeacher90MinSalary();
                }
            }
            //线上小班课
            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.HIGH_ONLINE)) {
                Integer studentNum = classGroupStudentMapperDao.countClassGroupNormalStudentNum(courseSchedule.getClassGroupId());
                if (studentNum < 3 || studentNum > 5) {
                    String numWaring = studentNum < 3 ? "小班课人数不能小于3," : "小班课人数不能大于5,";
                    throw new BizException( numWaring + "请调整");
                }
                salary = JSON.parseObject(teacherDefaultMusicGroupSalary.getSalaryRuleJson()).getBigDecimal(studentNum.toString());
            }

            if (courseSchedule.getType().equals(CourseSchedule.CourseScheduleType.MUSIC_NETWORK)) {
                salary = JSON.parseObject(teacherDefaultMusicGroupSalary.getSalaryRuleJson()).getBigDecimal("1");
            }

            courseScheduleTeacherSalary.setExpectSalary(salary);
        }
    }

    /**
     * @describe 创建课程指定教师的课酬记录-VIP课
     * @author Joburgess
     * @date 2020.10.22
     * @param courseSchedule: 课程计划
     * @param courseScheduleTeacherSalaries: 教师课酬记录基本信息
     * @return java.util.List<com.ym.mec.biz.dal.entity.CourseScheduleTeacherSalary>
     */
    private void createVipGroupCourseTeacherSalary(CourseSchedule courseSchedule, List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries){
        VipGroup vipGroup = vipGroupService.get(Long.valueOf(courseSchedule.getMusicGroupId()));
        for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
            Map<String, BigDecimal> salaryMap = vipGroupService.countVipGroupPredictFee(vipGroup, courseSchedule.getActualTeacherId(), null, null);
            courseScheduleTeacherSalary.setExpectSalary(courseSchedule.getTeachMode() == TeachModeEnum.OFFLINE?salaryMap.get("offlineTeacherSalary"):salaryMap.get("onlineTeacherSalary"));
        }
    }

    /**
     * @describe 创建课程指定教师的课酬记录-网管课
     * @author Joburgess
     * @date 2020.10.22
     * @param courseSchedule: 课程计划
     * @param courseScheduleTeacherSalaries: 教师课酬记录基本信息
     * @return java.util.List<com.ym.mec.biz.dal.entity.CourseScheduleTeacherSalary>
     */
    private void createPracticeGroupCourseTeacherSalary(CourseSchedule courseSchedule, List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries){
        List<Integer> teacherIds = courseScheduleTeacherSalaries.stream().map(CourseScheduleTeacherSalary::getUserId).collect(Collectors.toList());

        List<TeacherDefaultPracticeGroupSalary> allTeacherDefaultPracticeGroupSalaryList = teacherDefaultPracticeGroupSalaryDao.queryByUserIdList(teacherIds);
        Map<Integer, List<TeacherDefaultPracticeGroupSalary>> teacherSalaryMap = allTeacherDefaultPracticeGroupSalaryList.stream().collect(Collectors.groupingBy(TeacherDefaultPracticeGroupSalary::getUserId));
        for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
            final List<TeacherDefaultPracticeGroupSalary> teacherDefaultPracticeGroupSalaryList = teacherSalaryMap.get(courseScheduleTeacherSalary.getUserId());
            if (teacherDefaultPracticeGroupSalaryList != null && teacherDefaultPracticeGroupSalaryList.size() > 0) {
                courseScheduleTeacherSalary.setExpectSalary(teacherDefaultPracticeGroupSalaryList.get(0).getMainTeacherSalary());
            } else {
                throw new BizException("请设置老师 的网管课课酬");
            }
        }
    }

    @Override
    public List<TeacherAttendancesDto> getCourseTeachers(Long courseScheduleId) {
        List<TeacherAttendancesDto> result = new ArrayList<>();
        List<CourseScheduleTeacherSalary> courseScheduleTeacherSalaries = courseScheduleTeacherSalaryDao.findByCourseSchedule(courseScheduleId);
        if(CollectionUtils.isEmpty(courseScheduleTeacherSalaries)){
            return result;
        }
        Set<Integer> teacherIds = courseScheduleTeacherSalaries.stream().map(CourseScheduleTeacherSalary::getUserId).collect(Collectors.toSet());
        List<TeacherAttendance> teacherAttendances = teacherAttendanceDao.findByCourseSchedules(Arrays.asList(courseScheduleId));
        Map<Integer, TeacherAttendance> idTeacherAttendanceMap = teacherAttendances.stream().collect(Collectors.toMap(TeacherAttendance::getTeacherId, t -> t, (t1, t2) -> t1));
        List<SimpleUserDto> usersSimpleInfo = new ArrayList<>();
        if(!CollectionUtils.isEmpty(teacherIds)){
            usersSimpleInfo = teacherDao.getUsersSimpleInfo(new ArrayList<>(teacherIds));
        }
        Map<Integer, SimpleUserDto> idUserMap = usersSimpleInfo.stream().collect(Collectors.toMap(SimpleUserDto::getUserId, s -> s));

        CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleId);
        School school = schoolService.get(courseSchedule.getSchoolId());

        for (CourseScheduleTeacherSalary courseScheduleTeacherSalary : courseScheduleTeacherSalaries) {
            TeacherAttendancesDto t = new TeacherAttendancesDto();
            t.setTeacherId(courseScheduleTeacherSalary.getUserId());
            t.setTeacherName(idUserMap.containsKey(t.getTeacherId())?idUserMap.get(t.getTeacherId()).getUserName():"");
            t.setTeacherRole(courseScheduleTeacherSalary.getTeacherRole());
            if(idTeacherAttendanceMap.containsKey(t.getTeacherId())){
                TeacherAttendance teacherAttendance = idTeacherAttendanceMap.get(t.getTeacherId());
                t.setSignInTime(teacherAttendance.getSignInTime());
                t.setSignInStatus(Objects.nonNull(teacherAttendance.getSignInStatus())?(YesOrNoEnum.NO.equals(teacherAttendance.getSignInStatus())?SignInStatusEnum.UNUSUAL:SignInStatusEnum.NORMAL):SignInStatusEnum.NO);
                t.setSignOutTime(teacherAttendance.getSignOutTime());
                t.setSignOutStatus(Objects.nonNull(teacherAttendance.getSignOutStatus())?(YesOrNoEnum.NO.equals(teacherAttendance.getSignOutStatus())?SignOutStatusEnum.UNUSUAL:SignOutStatusEnum.NORMAL):SignOutStatusEnum.NO);
                t.setSignInLongitudeLatitude(teacherAttendance.getSignInLongitudeLatitude());
                t.setSignOutLongitudeLatitude(teacherAttendance.getSignOutLongitudeLatitude());
            }
            if(Objects.nonNull(school)){
                t.setSchoolLongitudeLatitude(school.getLongitudeLatitude());
            }
            result.add(t);
        }
        return result;
    }
}
