package cn.iocoder.yudao.module.course.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.base.constant.SchoolBaseConstants;
import cn.iocoder.yudao.module.base.entity.DlDriveSchoolStudent;
import cn.iocoder.yudao.module.base.mapper.DlDriveSchoolCourseMapper;
import cn.iocoder.yudao.module.base.service.DlDriveSchoolCourseService;
import cn.iocoder.yudao.module.base.entity.DriveSchoolCourseDeduct;
import cn.iocoder.yudao.module.base.service.DlDriveSchoolCourseDeductService;
import cn.iocoder.yudao.module.base.service.DlDriveSchoolStudentService;
import cn.iocoder.yudao.module.base.service.SchoolNotifyMessageSendService;
import cn.iocoder.yudao.module.base.vo.DlDriveSchoolCourseVO;
import cn.iocoder.yudao.module.base.vo.DlDriveSchoolStudentVO;
import cn.iocoder.yudao.module.course.entity.Process;
import cn.iocoder.yudao.module.course.entity.SchoolCommission;
import cn.iocoder.yudao.module.course.entity.SchoolCourseOrder;
import cn.iocoder.yudao.module.course.mapper.ProcessMapper;
import cn.iocoder.yudao.module.course.service.ProcessService;
import cn.iocoder.yudao.module.course.service.SchoolCommissionService;
import cn.iocoder.yudao.module.course.service.SchoolCourseOrderService;
import cn.iocoder.yudao.module.course.service.SchoolCourseSchemeService;
import cn.iocoder.yudao.module.course.vo.*;
import cn.iocoder.yudao.module.exam.entity.ExamBatch;
import cn.iocoder.yudao.module.exam.entity.ExamBatchItem;
import cn.iocoder.yudao.module.exam.mapper.ExamBatchMapper;
import cn.iocoder.yudao.module.exam.vo.ExamBatchItemVO;
import cn.iocoder.yudao.module.exam.vo.ExamVO;
import cn.iocoder.yudao.module.exam.mapper.ExamBatchItemMapper;
import cn.iocoder.yudao.module.exam.vo.ExamBatchItemNewVO;
import cn.iocoder.yudao.module.jx.domain.DriveSchoolDeduct;
import cn.iocoder.yudao.module.jx.service.IDriveSchoolDeductService;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.module.base.utils.DriveSchoolBaseUtil.getSubjectStr;


/**
 * 学员课程进度 Service 实现类
 *
 * @author 若依
 */
@Service
public class ProcessServiceImpl extends ServiceImpl<ProcessMapper, Process> implements ProcessService {
    @Autowired
    private ProcessMapper processMapper;
//        @Resource
//    private IDriveSchoolDeductService deductService;
    @Resource
    private AdminUserApi userApi;
    @Resource
    private SchoolCommissionService schoolCommissionService;

    @Resource
    private SchoolCourseOrderService schoolCourseOrderService;
    @Lazy
    @Resource
    private DlDriveSchoolStudentService dlDriveSchoolStudentService;
    @Autowired
    private ExamBatchItemMapper examBatchItemMapper;

    @Resource
    private ExamBatchMapper examBatchMapper;

    @Autowired
    private SchoolNotifyMessageSendService schoolNotifyMessageSendService;

    @Resource
    private DlDriveSchoolCourseService courseService;

    @Autowired
    private DlDriveSchoolCourseDeductService deductService;

    @Resource
    private IDriveSchoolDeductService driveSchoolDeductService;

    @Resource
    private SchoolCourseSchemeService schemeService;

    @Resource
    private RoleApi roleApi;

    @Resource
    private DictDataService dictDataService;


    /**
     * 教练查自己带教的课程和科目
     *
     * @return java.util.List<cn.iocoder.yudao.module.course.entity.Process>
     * @author vinjor-M
     * @date 11:05 2025/1/15
     **/
    @Override
    public List<Process> getMyCourseAndSubject() {
        //当前教练ID
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        LambdaQueryWrapper<Process> queryWrapper = new LambdaQueryWrapper<Process>()
                .eq(Process::getCoachId, userId)
                .notIn(Process::getSubject, Arrays.asList(1, 4))
                //状态不等于2-已完成的科目
//                .ne(Process::getStatus, "2")
                .groupBy(Process::getCourseId).groupBy(Process::getSubject);
        return this.list(queryWrapper);
    }

    /**
     * 教练查自己带教的课程和科目在训练中的学生-并且是未送考的
     *
     * @param process
     * @param page
     * @author vinjor-M
     * @date 17:11 2025/1/15
     **/
    @Override
    public IPage<Process> getMyCourseStudentPage(Process process, Page<Process> page) {
        //当前教练ID
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        process.setCoachId(userId);
//        processMapper.getMyCourseStudentPage(process, page);
        /*LambdaQueryWrapper<Process> queryWrapper = new LambdaQueryWrapper<Process>()
                .eq(Process::getCoachId, userId)
                .notIn(Process::getSubject, Arrays.asList(1, 4));
                *//*.eq(Process::getCourseId, process.getCourseId())
                .eq(Process::getSubject, process.getSubject());*//*
        if (process != null && process.getCourseId() != null) {
            queryWrapper.eq(Process::getCourseId, process.getCourseId());
        }
        if (process != null && process.getSubject() != null) {
            queryWrapper.eq(Process::getSubject, process.getSubject());
        }
        if (process != null && StringUtils.isNotEmpty(process.getUserName())) {
            queryWrapper.like(Process::getUserName, process.getUserName());
        }*/

        //状态等于1-训练中的
        /*if(dictDataService.getValueByTypeAndLabel("check_in_switch", "科二科三同时打卡开关").equals("0")){
            // 开关为0时，只查询状态为1的记录
            queryWrapper.eq(Process::getStatus, "1").groupBy(Process::getUserId);;
        } else {
            // 开关为1时，查询状态为0或1的记录
            queryWrapper.in(Process::getStatus, Arrays.asList("0", "1"));
        }

        // 其他查询条件
        queryWrapper.and(wrapper -> wrapper.isNull(Process::getExamStatus).or().eq(Process::getExamStatus, "0"))
                .orderByDesc(BaseDO::getCreateTime);*/
        /*queryWrapper.in(Process::getStatus, Arrays.asList("0", "1"))
                .and(wrapper -> wrapper.isNull(Process::getExamStatus).or().eq(Process::getExamStatus, "0"))
//                .groupBy(Process::getUserId)
                .orderByDesc(BaseDO::getCreateTime);
        // 需要查询订单表中是否终止
        return this.page(page, queryWrapper);*/
        return processMapper.getMyCourseStudentPage(process, page);
    }

    /**
     * 查某个学员在某个教练的某个课程、某个科目的学习进度（当前在练习中的）
     *
     * @param userId   学生id
     * @param courseId 课程id
     * @param subject  科目
     * @param coachId  教练id
     * @return cn.iocoder.yudao.module.course.entity.Process
     * @author vinjor-M
     * @date 18:39 2025/1/16
     **/
    @Override
    public Process getByStudentAndCourse(Long userId, String courseId, Integer subject, Long coachId, String examStatus) {
        LambdaQueryWrapper<Process> queryWrapper = new LambdaQueryWrapper<Process>()
                .eq(Process::getUserId, userId)
                .eq(Process::getCoachId, coachId)
                .eq(Process::getCourseId, courseId)
                .eq(Process::getSubject, subject)
                .in(Process::getStatus, Arrays.asList("0", "1"));
        if (null != examStatus) {
            queryWrapper.eq(Process::getExamStatus, examStatus);
        }
        queryWrapper.orderByDesc(BaseDO::getCreateTime);
        List<Process> processList = this.list(queryWrapper);
        return processList.isEmpty() ? null : processList.get(0);
    }

    @Override
    public List<Process> getByStudentAndCourseByUniqueCode(String uniqueCode) {
        DlDriveSchoolStudentVO dlDriveSchoolStudentVO = dlDriveSchoolStudentService.queryStudentByUniqueCode(uniqueCode);
        if(dlDriveSchoolStudentVO != null){
            Long coachId = SecurityFrameworkUtils.getLoginUserId();
            LambdaQueryWrapper<Process> queryWrapper = new LambdaQueryWrapper<Process>()
                    .eq(Process::getUserId, dlDriveSchoolStudentVO.getUserId())
                    .eq(Process::getCoachId, coachId)
                    .in(Process::getSubject, Arrays.asList(2, 3))
                    .in(Process::getStatus, Arrays.asList("0", "1"));

            /*if("0".equals(dictDataService.getValueByTypeAndLabel("check_in_switch", "科二科三同时打卡开关"))){
                // 开关为0时，只查询状态为1的记录
                queryWrapper.eq(Process::getStatus, "1");
            }else{
                // 开关为1时，查询状态为0或1的记录
                queryWrapper.in(Process::getStatus, Arrays.asList("0", "1"));
            }*/

            queryWrapper.orderByDesc(BaseDO::getCreateTime);
            return this.list(queryWrapper);
        }else{
            throw new RuntimeException("未查询到该学员信息，请向管理员核实");
        }
    }

    /**
     * 查学生当下正在学习中的学习进度
     *
     * @param userId TODO
     * @return cn.iocoder.yudao.module.course.entity.Process
     * @author vinjor-M
     * @date 15:18 2025/2/8
     **/
    @Override
    public Process selectByUserId(Long userId, Long coachId) {
        return processMapper.selectNewMaxByUserId(userId, coachId);
    }

    /**
     * 查询教练 每个科目已毕未毕业学生数量
     *
     * @param coachId 教练id
     * @return java.util.Map<java.lang.String, java.lang.Integer>
     * @author vinjor-M
     * @date 13:52 2025/2/10
     **/
    @Override
    public Map<String, Integer> selectByCoachId(Long coachId) {
        LambdaQueryWrapper<Process> queryWrapper = new LambdaQueryWrapper<Process>()
                .eq(Process::getCoachId, coachId);
        List<Process> allList = this.list(queryWrapper);
        //所有科目二的记录
        List<Process> subject2List = allList.stream().filter(item -> 2 == item.getSubject()).collect(Collectors.toList());
        //所有科目三的记录
        List<Process> subject3List = allList.stream().filter(item -> 3 == item.getSubject()).collect(Collectors.toList());
        //科目二未毕业学员id
        Set<Long> subject2No = new HashSet<>();
        //科目二已毕业学员id
        Set<Long> subject2Over = new HashSet<>();
        for (Process item : subject2List) {
            if ("2".equals(item.getStatus())) {
                //已完成
                if ("1".equals(item.getExamStatus())) {
                    //已通过考试
                    subject2Over.add(item.getUserId());
                }
            } else {
                //未完成
                subject2No.add(item.getUserId());
            }
        }
        //科目三未毕业学员id
        Set<Long> subject3No = new HashSet<>();
        //科目三已毕业学员id
        Set<Long> subject3Over = new HashSet<>();
        for (Process item : subject3List) {
            if ("2".equals(item.getStatus())) {
                //已完成
                if ("1".equals(item.getExamStatus())) {
                    //已通过考试
                    subject3Over.add(item.getUserId());
                }
            } else {
                //未完成
                subject3No.add(item.getUserId());
            }
        }
        Map<String, Integer> rtnMap = new HashMap<>();
        rtnMap.put("subject2No", subject2No.size());
        rtnMap.put("subject2Over", subject2Over.size());
        rtnMap.put("subject3No", subject3No.size());
        rtnMap.put("subject3Over", subject3Over.size());
        return rtnMap;
    }

    /**
     * 查某学生某课程累计总训练时长
     *
     * @param userId   学生ID
     * @param courseId 课程ID
     * @return java.lang.Double
     * @author vinjor-M
     * @date 14:17 2025/2/11
     **/
    @Override
    public Double getAllTrainTime(Long userId, String courseId) {
        return processMapper.selectAllTrainTime(userId, courseId);
    }

    /**
     * 分页查询学员课程进度
     *
     * @param page      分页参数
     * @param pageReqVO {@link ProcessVO}
     * @return com.baomidou.mybatisplus.core.metadata.IPage<cn.iocoder.yudao.module.course.vo.ProcessVO>
     * @author PQZ
     * @date 15:34 2025/2/17
     **/
    @Override
    public IPage<ProcessVO> pageProcess(Page<ProcessVO> page, ProcessVO pageReqVO) {
        return processMapper.pageProcess(pageReqVO, page);
    }
    @Override
    public IPage<ProcessVO> pageProcessNew(Page<ProcessVO> page, ProcessVO pageReqVO) {
        return processMapper.pageProcessNew(pageReqVO, page);
    }

    /**
     * 财务审核
     *
     * @param process {@link Process}
     * @author PQZ
     * @date 15:24 2025/2/18
     **/
    /*@Override
    @Transactional(rollbackFor = Exception.class)
    public void checkProcess(Process process) {
        //查询数据
        Process oldProcess = getById(process.getId());
        //查询当前登录用户信息
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO sysUser = userApi.getUser(userId);
        //如果是通过审核，需要保存考试记录
        if (process.getFinancePass()) {
            //根据科目查询规则
            if (null != process.getSubject()) {
                // 根据课程id查询配置
                DriveSchoolCourseDeduct deduct = deductService.getOne(Wrappers.<DriveSchoolCourseDeduct>lambdaQuery()
                        .eq(DriveSchoolCourseDeduct::getCourseId, process.getCourseId())
                        .eq(DriveSchoolCourseDeduct::getCourseSubject, process.getSubject()));
                //如果存在提成规则则生成提成记录
                if (null != deduct) {
                    SchoolCommission schoolCommission = new SchoolCommission();
                    //教练用户表id
                    schoolCommission.setCoachUserId(oldProcess.getCoachId());
                    //教练名称
                    schoolCommission.setCoachName(oldProcess.getCoachName());
                    //学生id
                    schoolCommission.setStudentId(oldProcess.getUserId());
                    //学生姓名
                    schoolCommission.setStudentName(oldProcess.getUserName());
                    //提成金额
                    schoolCommission.setCommissionAmount(deduct.getDeduct());
                    //课程id
                    schoolCommission.setCourseId(oldProcess.getCourseId());
                    //科目
                    schoolCommission.setSubject(oldProcess.getSubject().toString());
                    //审核人id
                    schoolCommission.setCheckId(sysUser.getId());
                    //审核人姓名
                    schoolCommission.setCheckName(sysUser.getNickname());

                    // 检查是否已存在记录
                    SchoolCommission existing = schoolCommissionService.getOne(
                            Wrappers.<SchoolCommission>lambdaQuery()
                                    .eq(SchoolCommission::getCoachUserId, schoolCommission.getCoachUserId())
                                    .eq(SchoolCommission::getStudentId, schoolCommission.getStudentId())
                                    .eq(SchoolCommission::getCourseId, schoolCommission.getCourseId())
                                    .eq(SchoolCommission::getSubject, schoolCommission.getSubject())
                    );

                    if(existing != null){
                        schoolCommission.setId(existing.getId());
                        schoolCommission.setDeleted(!process.getFinancePass());
                        schoolCommissionService.updateById(schoolCommission);
                    }else{
                        schoolCommissionService.save(schoolCommission);
                    }

                }
            }
        }
        updateById(process);
    }*/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkProcess(ProcessVO process) {
        // 查询原始数据和当前用户信息
        Process oldProcess = getById(process.getId());
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO sysUser = userApi.getUser(userId);

        // 科目为空时直接更新Process并返回
        if (process.getSubject() == null) {
            updateById(process);
            return;
        }

        if(!process.getFinancePass()){
            // 审核不通过需要发送站内信通知（姓名、科目、原因、时间、审核人）
            Long tenantId = TenantContextHolder.getTenantId();
            List<UserDTO> officeStaffList = roleApi.selectUserListByRoleCode(tenantId, "school_staff");

            if (officeStaffList != null && !officeStaffList.isEmpty()) {
                        String officeMessage = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_MEMBER_AUDIT_NOT_PASS, process.getUserName(), process.getStudentIdCard(), process.getCourseName(), process.getSubject(), process.getFinanceRemark());

                for (UserDTO staff : officeStaffList) {
                            schoolNotifyMessageSendService.sendMessage(staff.getId(), officeMessage, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, process.getTenantId());
                }
            }
        }

        // 查询提成规则
        /*DriveSchoolCourseDeduct deduct = deductService.getOne(
                Wrappers.<DriveSchoolCourseDeduct>lambdaQuery()
                        .eq(DriveSchoolCourseDeduct::getCourseId, process.getCourseId())
                        .eq(DriveSchoolCourseDeduct::getCourseSubject, process.getSubject())
        );*/

        // 如果存在提成规则
        if (process.getCoachCommission() != null) {
            // 构建提成记录对象
            SchoolCommission schoolCommission = new SchoolCommission();
            schoolCommission.setCoachUserId(oldProcess.getCoachId());
            schoolCommission.setCoachName(oldProcess.getCoachName());
            schoolCommission.setStudentId(oldProcess.getUserId());
            schoolCommission.setStudentName(oldProcess.getUserName());
            schoolCommission.setCommissionAmount(process.getCoachCommission());
            schoolCommission.setCourseId(oldProcess.getCourseId());
            schoolCommission.setSubject(String.valueOf(oldProcess.getSubject()));
            schoolCommission.setCheckId(sysUser.getId());
            schoolCommission.setCheckName(sysUser.getNickname());
            schoolCommission.setCheckRemark(process.getFinanceRemark());
            schoolCommission.setStudentIdCard(process.getStudentIdCard());
            schoolCommission.setExamTime(process.getExamTime());
            schoolCommission.setStudentPay(process.getStudentPay());

            // 检查是否已存在记录
            SchoolCommission existing = schoolCommissionService.getOne(
                    Wrappers.<SchoolCommission>lambdaQuery()
                            .eq(SchoolCommission::getCoachUserId, schoolCommission.getCoachUserId())
                            .eq(SchoolCommission::getStudentId, schoolCommission.getStudentId())
                            .eq(SchoolCommission::getCourseId, schoolCommission.getCourseId())
                            .eq(SchoolCommission::getSubject, schoolCommission.getSubject())
            );

            // 根据是否存在记录和审核状态处理
            if (existing != null) {
                if(process.getFinancePass()){
                    // 更新记录：设置ID和deleted状态
                    schoolCommission.setId(existing.getId());
                    schoolCommission.setDeleted(!process.getFinancePass());
                    schoolCommissionService.updateById(schoolCommission);
                }else {
                    // 删除记录：设置ID和deleted状态
                    schoolCommission.setId(existing.getId());
                    schoolCommission.setDeleted(!process.getFinancePass());
                    schoolCommissionService.removeById(existing.getId());

                }

            } else if (process.getFinancePass()) {

                Long tenantId = TenantContextHolder.getTenantId();
                List<UserDTO> officeStaffList = roleApi.selectUserListByRoleCode(tenantId, "cn");

                if (officeStaffList != null && !officeStaffList.isEmpty()) {
                    String officeMessage = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_MEMBER_AUDIT_PASS, process.getCoachName(), process.getUserName(), process.getStudentIdCard(), process.getCourseName(), process.getSubject());

                    for (UserDTO staff : officeStaffList) {
                        schoolNotifyMessageSendService.sendMessage(staff.getId(), officeMessage, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, tenantId);
                    }
                }
                // 将当前日期时间设置为发放时间
                schoolCommission.setPayTime(LocalDateTime.now());
                schoolCommission.setIfPay(true);
                // 仅审核通过时新增记录
                schoolCommission.setDeleted(false);
                schoolCommissionService.save(schoolCommission);
            }
        }

        // 更新Process记录
        updateById(process);
    }


    /**
     * 保存学员课程进度
     *
     * @param request {@link ProcessAddVO}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveProcess(ProcessAddVO request) {
        List<Process> processes = BeanUtil.copyToList(request.getProcessList(), Process.class);
        // 获取学生id和课程id
        String courseId = processes.get(0).getCourseId();
        Long userId = processes.get(0).getUserId();
        // 根据课程id和学生id查询进度
        List<Process> list = list(Wrappers.lambdaQuery(Process.class)
                .eq(Process::getCourseId, courseId)
                .eq(Process::getUserId, userId));

        //判断传递进来的进度集合中的课程id和教练id和课程id是否与查询出来的一致，如果一致在processes集合中删除
        for (Process process : list) {
            processes.removeIf(process1 -> process.getCourseId().equals(process1.getCourseId())
                    && process.getCoachId().equals(process1.getCoachId())
                    && process.getSubject().equals(process1.getSubject()));
        }

        if (CollUtil.isEmpty(processes)) {
            return;
        }
        // 校验详细信息
        verify(processes);
        // 保存信息
        this.saveBatch(processes);

        // 修改订单信息中的是否分配教练状态
        schoolCourseOrderService.update(Wrappers.lambdaUpdate(SchoolCourseOrder.class)
                .eq(SchoolCourseOrder::getId, request.getOrderId())
                .set(SchoolCourseOrder::getIfAssignmentCoach, SchoolBaseConstants.SCHOOL_COURSE_ORDER_IS_ASSIGN_COACH));

        // 查询进度
        List<Process> processList = list(Wrappers.lambdaQuery(Process.class)
                .eq(Process::getCourseId, courseId)
                .eq(Process::getUserId, userId));

        Process process = processList.stream()
                .filter(p -> "1".equals(p.getStatus()))
                .findFirst()
                .orElse(null);

        if (process == null) {
            // 没有进行中的
            Process maxCompleted = processList.stream()
                    .filter(p -> "2".equals(p.getStatus()))
                    .max(Comparator.comparing(Process::getSubject))
                    .orElse(null);

            if (maxCompleted != null) {
                // 尝试找 subject == maxCompleted + 1 的
                Process next = processList.stream()
                        .filter(p -> p.getSubject().equals(maxCompleted.getSubject() + 1))
                        .findFirst()
                        .orElse(null);

                process = next != null ? next : maxCompleted;
            } else {
                // 没有已完成的，找 subject 最小的
                process = processList.stream()
                        .min(Comparator.comparing(Process::getSubject))
                        .orElse(null);
            }
            process.setStatus("1");
            //更新
            updateById(process);
        }


        // 发送通知内容
        String message = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_ASSIGN_COACH,
                request.getProcessList().get(0).getCoachName(),
                request.getProcessList().get(1).getCoachName(),
                request.getProcessList().get(2).getCoachName(),
                request.getProcessList().get(3).getCoachName());

        // 发送消息给学员
        schoolNotifyMessageSendService.sendMessage(userId, message, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_MEMBER, request.getProcessList().get(0).getTenantId());

        // 发送消息给对应教练
        AdminUserRespDTO user = userApi.getUser(userId);
        String userName = user.getNickname();
        String userPhone = user.getMobile();
        String messageToCoach = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_ASSIGN_COACH_TO_COACH, userName, userPhone);
        schoolNotifyMessageSendService.sendMessage(request.getProcessList().get(0).getCoachId(), messageToCoach, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, request.getProcessList().get(0).getTenantId());

    }

    /**
     * 科目一、科目四考试成绩录入
     * @param process
     */
    @Override
    public void updateProcess(Process process) {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = userApi.getUser(userId);
        String userName = user.getNickname();
        update(Wrappers.lambdaUpdate(Process.class)
                .eq(Process::getUserId, process.getUserId())
                .eq(Process::getSubject, process.getSubject())
                .eq(Process::getCourseId, process.getCourseId())
                .eq(Process::getTenantId, process.getTenantId())
                .eq(Process::getDeleted, SchoolBaseConstants.COMMON_NO)
//                .set(process.getUserName() != null, Process::getUserName, process.getUserName())
                .set(process.getExamStatus() != null, Process::getExamStatus, process.getExamStatus())
                .set(process.getExamScore() != null, Process::getExamScore, process.getExamScore())
                .set(Process::getExamNum, process.getExamNum() + 1)
                .set(process.getRemark() != null, Process::getRemark, process.getRemark())
                .set(process.getExamTime() != null, Process::getExamTime, process.getExamTime())
                .set(process.getImages() != null, Process::getImages, process.getImages()));

        // 如果考试通过，则修改进度状态为已完成
        if (process.getExamStatus() != null && process.getExamStatus().equals("1")) {
            update(Wrappers.lambdaUpdate(Process.class)
                    .eq(Process::getUserId, process.getUserId())
                    .eq(Process::getSubject, process.getSubject())
                    .eq(Process::getCourseId, process.getCourseId())
                    .eq(Process::getTenantId, process.getTenantId())
                    .eq(Process::getDeleted, SchoolBaseConstants.COMMON_NO)
                    .set(Process::getStatus, 2));
            // 发送消息给教练
            String message = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_MEMBER_EXAM_SCORE, userName, "科目一", process.getExamScore(), "已通过");
            schoolNotifyMessageSendService.sendMessage(process.getCoachId(), message, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, process.getTenantId());
        } else if (process.getExamStatus() != null && !process.getExamStatus().equals("0")) {
            String message = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_MEMBER_EXAM_SCORE, userName, "科目一", process.getExamScore(), "未通过");
            schoolNotifyMessageSendService.sendMessage(process.getCoachId(), message, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, process.getTenantId());
        }
        // 如果是科目一且通过考试，修改科目二状态
        if (process.getSubject() == 1 && process.getExamStatus().equals("1")) {

            update(Wrappers.lambdaUpdate(Process.class)
                    .eq(Process::getUserId, process.getUserId())
                    .eq(Process::getSubject, 2)
                    .eq(Process::getCourseId, process.getCourseId())
                    .eq(Process::getDeleted, SchoolBaseConstants.COMMON_NO)
                    .set(Process::getStatus, SchoolBaseConstants.PROCESS_STATUS_IN_PROGRESS));
        }
        // 如果是科目四且通过考试，修改学员考试通过状态
        if (process.getSubject() == 4 && process.getExamStatus().equals("1")) {
            dlDriveSchoolStudentService.updateStudentPassAndGradTime(process.getExamTime(), process.getUserId(), process.getCourseId(), process.getTenantId());
            String message = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_MEMBER_EXAM_SCORE, userName, "科目四", process.getExamScore(), "已通过");
            schoolNotifyMessageSendService.sendMessage(process.getCoachId(), message, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, process.getTenantId());
        } else if (process.getSubject() == 4 && process.getExamStatus().equals("0")) {
            String message = String.format(SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TEMPLATE_MEMBER_EXAM_SCORE, userName, "科目四", process.getExamScore(), "未通过");
            schoolNotifyMessageSendService.sendMessage(process.getCoachId(), message, SchoolBaseConstants.SCHOOL_NOTIFY_MESSAGE_TYPE_ADMIN, process.getTenantId());
        }

    }

    /**
     * 根据用户id和课程id查询所有进度
     *
     * @param userId   用户id
     * @param courseId 课程id
     * @return java.util.List<cn.iocoder.yudao.module.course.vo.ProcessVO>
     */
    @Override
    public List<ProcessVO> getAllByUserIdAndCourseId(Long userId, String courseId) {
        if (null != userId && null != courseId) {
            List<Process> processList = processMapper.selectList(Wrappers.lambdaQuery(Process.class)
                    .eq(Process::getUserId, userId)
                    .eq(Process::getCourseId, courseId));
            return BeanUtil.copyToList(processList, ProcessVO.class);
        }
        return null;
    }

    /**
     * 根据userId查询考试列表
     *
     * @param userId 用户id
     */
    @Override
    public List<ProcessVO> getExamListByUserId(Long userId) {
        if (userId == null) {
            return null;
        }
        List<Process> processList = processMapper.selectList(
                Wrappers.lambdaQuery(Process.class)
                        .eq(Process::getUserId, userId)
                        .in(Process::getStatus, Arrays.asList("1", "2"))
                        .in(Process::getSubject, Arrays.asList(1, 4))
                        .isNotNull(Process::getExamScore)
        );
        return BeanUtil.copyToList(processList, ProcessVO.class);
    }

    /**
     * 根据userId查询考试列表
     *
     * @param userId 用户id
     */
    @Override
    public List<ExamVO> getExamListByUserIdTest(Long userId) {
        if (userId == null) {
            return Collections.emptyList();
        }
        List<Process> processList = processMapper.selectList(
                Wrappers.lambdaQuery(Process.class)
                        .eq(Process::getUserId, userId)
                        .in(Process::getStatus, Arrays.asList("1", "2"))
                        .in(Process::getSubject, Arrays.asList(1, 4))
                        .isNotNull(Process::getExamScore)
                        .orderByDesc(Process::getExamTime)
        );
        List<ExamVO> examBatchItemNew = examBatchItemMapper.selectExamByUserIdAndCoachId(userId, null);

        List<ExamVO> result = new ArrayList<>();
        result.addAll(BeanUtil.copyToList(processList, ExamVO.class));
        result.addAll(examBatchItemNew);
        return result;
    }

    @Override
    public List<ExamVO> getExamListByUserIdTestNew(Long userId) {
        if (userId == null) {
            return Collections.emptyList();
        }
        List<Process> processList = processMapper.selectList(
                Wrappers.lambdaQuery(Process.class)
                        .eq(Process::getUserId, userId)
                        .in(Process::getStatus, Arrays.asList("1", "2"))
                        .in(Process::getSubject, Arrays.asList(1, 4))
                        .isNotNull(Process::getExamScore)
                        .orderByDesc(Process::getExamTime)
        );
        List<ExamVO> examBatchItemNew = examBatchItemMapper.selectExamByUserIdAndCoachIdNew(userId, null);

        List<ExamVO> result = new ArrayList<>();
        result.addAll(BeanUtil.copyToList(processList, ExamVO.class));
        result.addAll(examBatchItemNew);
        return result;
    }

    private static void verify(List<Process> processes) {
        for (Process process : processes) {
            // 校验状态
            if (StrUtil.isBlank(process.getStatus())) {
                throw new RuntimeException("状态不能为空");
            }
            // 校验科目
            if (null == process.getSubject()) {
                throw new RuntimeException("科目不能为空");
            }
            if (StrUtil.isBlank(process.getCourseId())) {
                throw new RuntimeException("课程ID不能为空");
            }
            if (StrUtil.isBlank(process.getCourseName())) {
                throw new RuntimeException("课程名称不能为空");
            }
            if (null == process.getUserId()) {
                throw new RuntimeException("用户ID不能为空");
            }
            if (StrUtil.isBlank(process.getUserName())) {
                throw new RuntimeException("用户名称不能为空");
            }
            if (StrUtil.isBlank(process.getUserMobile())) {
                throw new RuntimeException("用户手机号不能为空");
            }
            if (null == process.getCoachId()) {
                throw new RuntimeException("教练ID不能为空");
            }
            if (StrUtil.isBlank(process.getCoachName())) {
                throw new RuntimeException("教练名称不能为空");
            }
        }
    }

    /**
     * 教练自招自动分配教练
     */
    @Override
    public void autoAssignCoach(ProcessNewVO request){
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = userApi.getUser(userId);
//        String userName = user.getNickname();
        String userName= request.getUserName();
        String  mobile = user.getMobile();

        DlDriveSchoolCourseVO dlDriveSchoolCourseVO = courseService.queryDetailById(request.getCourseId());
        ProcessAddVO processVo = new ProcessAddVO();
        List<ProcessVO> processList = new ArrayList<>();

        for (int subject = 1; subject <= 4; subject++) {
            ProcessVO processVO = new ProcessVO();
            processVO.setSubject(subject);
            if(subject == 1){
                processVO.setStatus("1");
            }else{
                processVO.setStatus("0");
            }
            processVO.setUserId(userId);
            processVO.setCourseId(dlDriveSchoolCourseVO.getId());
            processVO.setCourseName(dlDriveSchoolCourseVO.getName());
            processVO.setCourseType(dlDriveSchoolCourseVO.getType());
            processVO.setUserName(userName);
            processVO.setUserMobile(mobile);
            processVO.setCoachId(request.getCoachId());
            processVO.setCoachName(request.getCoachName());
            processVO.setExamStatus(null);

            processList.add(processVO);
        }

        // 组装ProcessAddVO

        processVo.setProcessList(processList);
        ProcessAddVO processAddVO = new ProcessAddVO();
        processAddVO.setProcessList(processList);
        processAddVO.setOrderId(request.getOrderId());

        // 修改订单状态为已支付
        schoolCourseOrderService.update(Wrappers.lambdaUpdate(SchoolCourseOrder.class)
                .eq(SchoolCourseOrder::getId, request.getOrderId())
                .set(SchoolCourseOrder::getIfAssignmentCoach, SchoolBaseConstants.SCHOOL_COURSE_ORDER_IS_ASSIGN_COACH)
                .set(SchoolCourseOrder::getPaymentStatus, "2"));
        this.saveProcess(processAddVO);
    }

    @Override
    public ProcessAndExamBatchVO getProcessAndBatch(String id) {
        ProcessAndExamBatchVO processAndExamBatchVO = new ProcessAndExamBatchVO();
        Process process = processMapper.selectById(id);
        BeanUtils.copyProperties(process, processAndExamBatchVO);
        if (process != null) {
           String courseId = process.getCourseId();
           Long coachId = process.getCoachId();
           int subject = process.getSubject();
           double fraction = process.getExamScore();
           Long userId = process.getUserId();
           ProcessAndExamBatchVO processAndBatch = processMapper.getProcessAndBatch(courseId, coachId, subject, fraction, userId);

            if (processAndBatch != null) {
                processAndExamBatchVO.setBatchId(processAndBatch.getBatchId());
                processAndExamBatchVO.setBatchItemId(processAndBatch.getBatchItemId());
                processAndExamBatchVO.setAddr(processAndBatch.getAddr());
                processAndExamBatchVO.setAddrId(processAndBatch.getAddrId());
                processAndExamBatchVO.setTransWay(processAndBatch.getTransWay());
                processAndExamBatchVO.setStartTime(processAndBatch.getStartTime());
                processAndExamBatchVO.setEndTime(processAndBatch.getEndTime());AdminUserRespDTO user = userApi.getUser(userId);
            }
        }

        return processAndExamBatchVO;
    }

    /**
     * 根据进度id查询进度详情
     *
     */
    @Override
    public ProcessVO getDlDriveSchoolCoach(String id) {
//        ProcessVO processVO = BeanUtils.toBean(this.getById(id), ProcessVO.class);
        ProcessVO processVO = new ProcessVO();
        BeanUtil.copyProperties(this.getById(id), processVO);
        Long coachId = processVO.getCoachId();
        Integer subject = processVO.getSubject();
        Long userId = processVO.getUserId();
        String courseId = processVO.getCourseId();
        BigDecimal deduct = BigDecimal.ZERO;
        String schemeId = schoolCourseOrderService.getSchemeByStudentId(userId, courseId, subject);
        if(schemeId == null){
            deduct = schemeService.getCourseDeduct(courseId, subject);
            if(deduct == null){
                DriveSchoolDeduct schoolDeduct = driveSchoolDeductService.queryBySubject(subject.toString());
                if (schoolDeduct != null && schoolDeduct.getDeduct() != null) {
                    deduct = schoolDeduct.getDeduct();
                }
            }
        }else{
            deduct = schemeService.getSchemeById(schemeId, subject);
            if(deduct == null){
                DriveSchoolDeduct schoolDeduct = driveSchoolDeductService.queryBySubject(subject.toString());
                if (schoolDeduct != null && schoolDeduct.getDeduct() != null) {
                    deduct = schoolDeduct.getDeduct();
                }
            }
        }
        /*DriveSchoolCourseDeduct courseDeduct = deductService.getDeductByCourseIdAndSubject(courseId, subject);
        if (courseDeduct != null) {
            if (courseDeduct.getDeduct() != null) {
                deduct = courseDeduct.getDeduct();
            }
            else if (courseDeduct.getCourseSubject() != null) {
                DriveSchoolDeduct schoolDeduct = driveSchoolDeductService.queryBySubject(courseDeduct.getCourseSubject());
                if (schoolDeduct != null && schoolDeduct.getDeduct() != null) {
                    deduct = schoolDeduct.getDeduct();
                }
            }
        }*/
        List<SchoolCourseOrderVO> courseByInfo = schoolCourseOrderService.getCourseByInfo(userId, courseId);
        BigDecimal studentPay = BigDecimal.ZERO;
        BigDecimal studentRemainingPay = BigDecimal.ZERO;
        BigDecimal discount = BigDecimal.ZERO;
        BigDecimal actualPayment = BigDecimal.ZERO;
        String studentIdCard = null;
        String cashierConfirm = null;
        String orderRemark = null;
        String cashierConfirmRemark = null;
        LocalDateTime createTime = null;
        if (!courseByInfo.isEmpty()) {
            studentPay = courseByInfo.get(0).getReserveMoney() != null ?
                    courseByInfo.get(0).getReserveMoney() : BigDecimal.ZERO;
            studentRemainingPay = courseByInfo.get(0).getRestMoney() != null ?
                    courseByInfo.get(0).getRestMoney() : BigDecimal.ZERO;
            studentIdCard = courseByInfo.get(0).getUserNo() != null ?
                    courseByInfo.get(0).getUserNo() : null;
            cashierConfirm = courseByInfo.get(0).getCashierConfirm()!= null?
                    courseByInfo.get(0).getCashierConfirm() : null;
            orderRemark = courseByInfo.get(0).getOrderRemark()!= null?
                    courseByInfo.get(0).getOrderRemark() : null;
            discount = courseByInfo.get(0).getDiscount() != null ?
                    courseByInfo.get(0).getDiscount() : BigDecimal.ZERO;
            actualPayment = courseByInfo.get(0).getActualPayment() != null ?
                    courseByInfo.get(0).getActualPayment() : BigDecimal.ZERO;
            cashierConfirmRemark = courseByInfo.get(0).getCashierConfirmRemark()!= null?
                    courseByInfo.get(0).getCashierConfirmRemark() : null;
            createTime = courseByInfo.get(0).getCreateTime();
        }
        processVO.setCoachCommission(deduct);
        processVO.setStudentPay(studentPay);
        processVO.setDiscount(discount);
        processVO.setActualPayment(actualPayment);
        processVO.setStudentRemainingPay(studentRemainingPay);
        processVO.setStudentIdCard(studentIdCard);
        processVO.setCashierConfirm(cashierConfirm);
        processVO.setOrderRemark(orderRemark);
        processVO.setCashierConfirmRemark(cashierConfirmRemark);
        processVO.setCreateTime(createTime);

        DlDriveSchoolStudent studentByUserId = dlDriveSchoolStudentService.getStudentByUserId(userId);
        if(studentByUserId != null){
            if(studentByUserId.getChannel() != null){
                processVO.setChannel(studentByUserId.getChannel());
            }
            if(studentByUserId.getSource() != null){
                processVO.setSource(studentByUserId.getSource());
            }
        }
        List<Process> list = this.lambdaQuery()
                .eq(Process::getCoachId, processVO.getCoachId())
                .eq(Process::getCourseId, processVO.getCourseId())
                .eq(Process::getUserId, processVO.getUserId())
                .eq(Process::getDeleted, false)
                .orderByAsc(Process::getSubject)
                .list();
        processVO.setProcessList(list);
        return processVO;
    }

    /**
     * 在录入成绩出修改教练
     */
    @Override
    public Boolean updateCoachForScoreInput(String id, Long coachId, String coachName) {
        Process process = processMapper.selectById(id);
        if (process == null) {
            return false;
        }
        process.setCoachId(coachId);
        process.setCoachName(coachName);
        int updateCount;
        if(process.getSubject() == 1 || process.getSubject() == 4){
            // 不生成批次信息
            updateCount = processMapper.updateById(process);
        }else{
            // 科二和科三会生成批次信息，如果有批次信息需要修改批次信息
            updateCount = processMapper.updateById(process);
            ExamBatch batchIdForProcess = processMapper.getBatchForProcess(process);
            if(batchIdForProcess != null){
                List<ExamBatchItemVO> batchItemVOList = examBatchItemMapper.getBatchItemCount(batchIdForProcess.getId());
                if(batchItemVOList.size() == 1){
                    ExamBatch examBatch = examBatchMapper.selectById(batchIdForProcess);
                    examBatch.setCoachId(process.getCoachId());
                    examBatch.setCoachName(process.getCoachName());
                    examBatchMapper.updateById(examBatch);
                    // 如果数量大于1，则需要新建批次和批次明细数据
                }else if(batchItemVOList.size() > 1){
                    // 先通过batchId和userId 获取对应数据，通过id进行删除
                    LambdaQueryWrapper<ExamBatchItem> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(ExamBatchItem::getBatchId, batchIdForProcess)
                            .eq(ExamBatchItem::getUserId, process.getUserId())
                            .eq(ExamBatchItem::getDeleted, false);
                    List<ExamBatchItem> batchItems = examBatchItemMapper.selectList(wrapper);
                    // 将之前的数据拷贝，并设置新的id和教练
                    ExamBatch newExamBatch = new ExamBatch();
                    BeanUtils.copyProperties(batchIdForProcess, newExamBatch, "id");
                    newExamBatch.setId(this.getUUID());
                    newExamBatch.setCoachId(process.getCoachId());
                    newExamBatch.setCoachName(process.getCoachName());
                    newExamBatch.setBatchName(newExamBatch.getBatchName() + "1");
                    examBatchMapper.insert(newExamBatch);
                    for (ExamBatchItem batchItem : batchItems) {
                        if(Objects.equals(batchIdForProcess.getId(), batchItem.getBatchId())){
                            batchItem.setBatchId(newExamBatch.getId());
                            examBatchItemMapper.updateById(batchItem);
                        }

                    }
                }
            }
        }
        if(updateCount > 0){
            return true;
        }else{
            return false;
        }
    }

    /**
     * 已毕业学员统计
     */
    @Override
    public List<Map<String, Object>> getGraduateStudent(String courseType) {
        List<Process> rawList = processMapper.getGraduateStudent(courseType);

        Map<Long, Map<String, Object>> resultMap = new HashMap<>();

        for (Process row : rawList) {
            Long coachId = row.getCoachId();
            String coachName = row.getCoachName();
            String courseTypeVal = row.getCourseType();
            String images  = row.getImages();
            Long userId = row.getUserId();

            // 先确保教练一定加入 map
            Map<String, Object> coachMap = resultMap.computeIfAbsent(coachId, k -> {
                Map<String, Object> m = new HashMap<>();
                m.put("coachId", coachId);
                m.put("coachName", coachName);
                m.put("studentCount", 0);
                m.put("images", images);
                return m;
            });

            // 有学员才进行统计
            if (userId != null) {
                // 统计总数
                int count = (int) coachMap.get("studentCount");
                coachMap.put("studentCount", count + 1);

                // 统计各课程类型数量
                if (courseTypeVal != null) {
                    String key = courseTypeVal + "Num";
                    int typeCount = (int) coachMap.getOrDefault(key, 0);
                    coachMap.put(key, typeCount + 1);
                }
            }
        }

        // 按照总数倒序排序
        return resultMap.values().stream()
                .sorted((a, b) -> ((Integer) b.get("studentCount")).compareTo((Integer) a.get("studentCount")))
                .collect(Collectors.toList());
    }

    /**
     * 未毕业学员统计
     */
    @Override
    public List<Map<String, Object>> getNoGraduateStudent(String courseType) {
        List<Process> rawList = processMapper.getNoGraduateStudent(courseType);

        Map<Long, Map<String, Object>> resultMap = new HashMap<>();

        for (Process row : rawList) {
            Long coachId = row.getCoachId();
            String coachName = row.getCoachName();
            String courseTypeVal = row.getCourseType();
            String images  = row.getImages();
            Long userId = row.getUserId();

            // 先确保教练一定加入 map
            Map<String, Object> coachMap = resultMap.computeIfAbsent(coachId, k -> {
                Map<String, Object> m = new HashMap<>();
                m.put("coachId", coachId);
                m.put("coachName", coachName);
                m.put("studentCount", 0);
                m.put("images", images);
                return m;
            });

            // 有学员才进行统计
            if (userId != null) {
                // 统计总数
                int count = (int) coachMap.get("studentCount");
                coachMap.put("studentCount", count + 1);

                // 统计各课程类型数量
                if (courseTypeVal != null) {
                    String key = courseTypeVal + "Num";
                    int typeCount = (int) coachMap.getOrDefault(key, 0);
                    coachMap.put(key, typeCount + 1);
                }
            }
        }

        // 按照总数倒序排序
        return resultMap.values().stream()
                .sorted((a, b) -> ((Integer) b.get("studentCount")).compareTo((Integer) a.get("studentCount")))
                .collect(Collectors.toList());
    }

    /**
     * 获取 科目二/三 通过学员
     */
    @Override
    public IPage<ProcessVO> getPassStudent(Long coachId, int subject, String courseType, String name, String sort, Page<ProcessVO> page) {
        return processMapper.getPassStudent(coachId, subject, courseType, name, sort, page);
    }

    /**
     * 获取 科目二/三 通过学员
     */
    @Override
    public List<ProcessVO> getPassStudentList(Long coachId, int subject, String startTime, String endTime) {
        return processMapper.getPassStudentList(coachId, subject, startTime, endTime);
    }

    /**
     * 需要导出的数据
     */
    @Override
    public IPage<ProcessExportVO> getProcessExportData(ProcessExportVO exportVO, Page<ProcessExportVO> page) {
        return processMapper.getProcessExportData(exportVO, page);
    }

    @Override
    public ProcessExportVO getSubjectPassCount(ProcessExportVO exportVO) {
        return processMapper.getSubjectPassCount(exportVO);
    }


    /**
     * 导出数据的三种形式
     * @param exportVO
     * @return
     */
    @Override
    public List<ProcessExportVO> getProcessList(ProcessExportVO exportVO) {
        // 分页查询当前页
        Page<ProcessExportVO> page = new Page<>(exportVO.getPageNo(), exportVO.getPageSize());
        IPage<ProcessExportVO> result = processMapper.getProcessExportData(exportVO, page);
        return result.getRecords();
    }

    @Override
    public List<ProcessExportVO> getAllProcessList(ProcessExportVO exportVO) {
        // 不分页查询全部数据
        Page<ProcessExportVO> page = new Page<>(1, Integer.MAX_VALUE);
        IPage<ProcessExportVO> result = processMapper.getProcessExportData(exportVO, page);
        return result.getRecords();
    }

    @Override
    public List<ProcessExportVO> getProcessListByRange(ProcessExportVO exportVO) {
        List<ProcessExportVO> allData = new ArrayList<>();

        // 循环查询指定范围内的数据
        for (int i = exportVO.getStartPage(); i <= exportVO.getEndPage(); i++) {
            Page<ProcessExportVO> page = new Page<>(i, exportVO.getPageSize());
            IPage<ProcessExportVO> result = processMapper.getProcessExportData(exportVO, page);
            allData.addAll(result.getRecords());

            // 如果已经到达最后一页，提前结束循环
            if (i >= result.getPages()) {
                break;
            }
        }
        return allData;
    }





    /**
     * 学员考试合格率计算
     */
    @Override
    public List<ExamPassRateVO> getExamPassRate(Integer subject, Long coachId, String timeType, String startTimeStr, String endTimeStr) {
        String startTime = "";
        String endTime = "";
        if("more".equals(timeType)){
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(startTimeStr)){
                startTime = startTimeStr+" 00:00:01";
            }
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(endTimeStr)) {
                endTime = endTimeStr + " 23:59:59";
            }
        }else if("month".equals(timeType)){
            //当月
            startTime = DateUtil.format(DateUtil.beginOfMonth(DateUtil.date()),"yyyy-MM-dd")+" 00:00:01";
            endTime = DateUtil.format(DateUtil.endOfMonth(DateUtil.date()),"yyyy-MM-dd")+" 23:59:59";
        }else if("day".equals(timeType)){
            //当天
            startTime = DateUtil.formatDate(DateUtil.date())+" 00:00:01";
            endTime = DateUtil.formatDate(DateUtil.date())+" 23:59:59";
        }

        return processMapper.getOverallPassingRate(subject, coachId, startTime, endTime);
    }

    /**
     * 学员考试合格率计算
     */
    @Override
    public List<CoachExamPassRateVO> getPassingRateByCoachId(Long coachId, String timeType, String startTimeStr, String endTimeStr) {
        String startTime = "";
        String endTime = "";
        if("more".equals(timeType)){
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(startTimeStr)){
                startTime = startTimeStr+" 00:00:01";
            }
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(endTimeStr)) {
                endTime = endTimeStr + " 23:59:59";
            }
        }else if("month".equals(timeType)){
            //当月
            startTime = DateUtil.format(DateUtil.beginOfMonth(DateUtil.date()),"yyyy-MM-dd")+" 00:00:01";
            endTime = DateUtil.format(DateUtil.endOfMonth(DateUtil.date()),"yyyy-MM-dd")+" 23:59:59";
        }else if("day".equals(timeType)){
            //当天
            startTime = DateUtil.formatDate(DateUtil.date())+" 00:00:01";
            endTime = DateUtil.formatDate(DateUtil.date())+" 23:59:59";
        }

        return processMapper.getPassingRateByCoachId(coachId, startTime, endTime);
    }

    /**
     * 考试通过率计算获取
     */
    @Override
    public IPage<StudentPassInfoVO> getPassedStudentsByCoachAndExamNum(String timeType, Long coachId, Integer subject, Integer examNum, String name, String courseType ,String startTimeStr, String endTimeStr, Page<StudentPassInfoVO> page) {
        String startTime = "";
        String endTime = "";
        if("more".equals(timeType)){
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(startTimeStr)){
                startTime = startTimeStr+" 00:00:01";
            }
            if(org.apache.commons.lang3.StringUtils.isNotEmpty(endTimeStr)) {
                endTime = endTimeStr + " 23:59:59";
            }
        }else if("month".equals(timeType)){
            //当月
            startTime = DateUtil.format(DateUtil.beginOfMonth(DateUtil.date()),"yyyy-MM-dd")+" 00:00:01";
            endTime = DateUtil.format(DateUtil.endOfMonth(DateUtil.date()),"yyyy-MM-dd")+" 23:59:59";
        }else if("day".equals(timeType)){
            //当天
            startTime = DateUtil.formatDate(DateUtil.date())+" 00:00:01";
            endTime = DateUtil.formatDate(DateUtil.date())+" 23:59:59";
        }

        return processMapper.getPassedStudentsByCoachAndExamNum(coachId, subject, examNum, name, courseType, startTime, endTime, page);
    }


    /**
     * 生成32位uuid
     */
    public String getUUID() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString().replace("-", "");
    }



}
