package jnpf.cultivate.v2.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jnpf.cultivate.mapper.CultivateExamMapper;
import jnpf.cultivate.mapper.FtbCultivateCertificateResultMapper;
import jnpf.cultivate.mapper.FtbCultivateExamUserMapper;
import jnpf.cultivate.service.*;
import jnpf.cultivate.service.impl.FtbCultivatePositionCourseExamService;
import jnpf.cultivate.service.impl.FtbCultivatePositionCourseIdentityService;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.cultivate.v2.service.*;
import jnpf.entity.cultivate.*;
import jnpf.enums.cultivate.ApplyStatusEnum;
import jnpf.model.cultivate.dto.learn.BatchCommonCountDto;
import jnpf.model.cultivate.po.FtbCultivatePositionCourseCertificate;
import jnpf.model.cultivate.po.course.FtbCultivateCertificateResult;
import jnpf.model.cultivate.po.course.FtbCultivateCourse;
import jnpf.model.cultivate.po.exam.FtbCultivateExamUser;
import jnpf.model.cultivate.po.position.*;
import jnpf.model.cultivate.po.promotion.FtbCultivatePromotionLog;
import jnpf.model.cultivate.po.promotion.FtbCultivatePromotionMemberNew;
import jnpf.model.cultivate.po.promotion.FtbCultivatePromotionPostNew;
import jnpf.model.cultivate.v2.exam.po.CultivateExam;
import jnpf.model.cultivate.v2.exam.po.CultivateExamDrawRule;
import jnpf.model.cultivate.v2.mq.CultivateMqDTO;
import jnpf.model.cultivate.v2.position.vo.CheckPostAndGradeResult;
import jnpf.model.cultivate.v2.position.vo.FtbCultivatePositionCourseWithNameVo;
import jnpf.model.cultivate.v2.position.vo.PositionStatusResultVo;
import jnpf.model.cultivate.v2.position.vo.V2AllCultivatePositionCourseExam;
import jnpf.model.cultivate.v2.promotion.vo.MyCultivatePromotionListVo;
import jnpf.model.cultivate.v2.promotion.vo.V2CultivatePostAndGradeVoExt;
import jnpf.model.cultivate.vo.identify.UserOrgInfoAll1Vo;
import jnpf.model.enums.CourseEnums;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.util.ConstantUtil;
import jnpf.util.QuestionAnalysisUtil;
import jnpf.util.RandomUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class V2CultivatePostStudyServiceImpl implements V2CultivatePostStudyService {


    @Autowired
    private FtbCultivatePositionService ftbCultivatePositionService;

    @Autowired
    private FtbCultivatePositionCourseService ftbCultivatePositionCourseService;

    @Autowired
    private FtbCultivatePositionCourseExamService ftbCultivatePositionCourseExamService;

    @Autowired
    private FtbCultivatePositionCourseIdentityService ftbCultivatePositionCourseIdentityService;

    @Autowired
    private FtbCultivatePositionCoursePracticeService ftbCultivatePositionCoursePracticeService;

    @Autowired
    private FtbCultivatePositionCourseCertificateService ftbCultivatePositionCourseCertificateService;

    @Autowired
    private V2CultivateBatchQueryService v2CultivateBatchQueryService;

    @Autowired
    private FtbCultivatePositionSettingService ftbCultivatePositionSettingService;


    @Autowired
    private FtbCultivatePositionLogService ftbCultivatePositionLogService;


    @Autowired
    private FtbCultivateCourseService ftbCultivateCourseService;

    @Autowired
    private CultivateIdentifyTableService identifyTableService;

    @Autowired
    private CultivateIdentifyItemsService identifyItemsService;

    @Autowired
    private CultivateIdentifyApplyDetailsService applyDetailsService;

    @Autowired
    private CultivateIdentifyApplyService identifyApplyService;

    @Autowired
    private CultivateIdentifyApplyTableBackupsService applyTableBackupsService;

    @Autowired
    private CultivateIdentifyApplyDetailsBackupsService applyDetailsBackupsService;

    @Autowired
    private FtbCultivatePromotionLogService ftbCultivatePromotionLogService;

    @Autowired
    private V2CultivateCertificateService v2CultivateCertificateService;


    @Autowired
    private CultivateExamDrawRuleService examDrawRuleService;

    @Autowired
    private FtbCultivatePromotionUserService ftbCultivatePromotionUserService;

    @Autowired
    private FtbCultivatePromotionMemberNewService ftbCultivatePromotionMemberNewService;

    @Autowired
    private FtbCultivatePromotionPostNewService ftbCultivatePromotionPostNewService;

    @Autowired
    private UserApiV2Util userApiV2Util;

    @Autowired
    private FtbCultivateExamUserMapper ftbCultivateExamUserMapper;


    @Autowired
    private FtbCultivateCertificateResultMapper ftbCultivateCertificateResultMapper;


    @Autowired
    private CultivatePositionCourseLogService cultivatePositionCourseLogService;


    @Autowired
    private CultivateExamMapper v2CultivateExamMapper;


    @Autowired
    private ApplicationContext applicationContext;

    private V2CultivatePostStudyService selfProxy;

    @PostConstruct
    public void init() {
        this.selfProxy = applicationContext.getBean(V2CultivatePostStudyService.class);
    }

    /**
     * 岗位学习
     *
     * @param message 培训信息
     */
    @Override
    @Transactional
    public void dealPositionCourseStudy(CultivateMqDTO message) {
        String userId = message.getUserId();
        String courseId = message.getBusinessId();
        String positionLearnId = message.getBusinessSourceId();//岗位学习id
        String tenantId = message.getTenantId();

        if (StringUtils.isEmpty(positionLearnId) || StringUtils.isEmpty(courseId) || StringUtils.isEmpty(userId)) {
            return;
        }
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未null，courseId={}, userId={}", courseId, userId);
            return;
        }
        //查询岗位学习的基本信息
        FtbCultivatePosition position = ftbCultivatePositionService.getById(positionLearnId);
        if (position == null) {
            log.error("dealPositionCourse positionLearnId={}，未查询到岗位学习", positionLearnId);
            return;
        }


        String gradeId = "";
        String postId = position.getPostId();
        // 查询岗位学习课程表 - 使用新封装的方法
        FtbCultivatePositionSetting positionSetting;
        List<FtbCultivatePositionCourseWithNameVo> courseList;

        if (position.getIsConfiguredToGrade().equals(0)) {
            courseList = ftbCultivatePositionCourseService.listByPostLearnId(positionLearnId, courseId);
            positionSetting = ftbCultivatePositionSettingService.listByPostLearnId(positionLearnId);
        } else {
            if (message.getParams() == null || message.getParams().get(CultivateMqDTO.GRADE_ID) == null) {
                log.error("dealPositionCourse positionLearnId={}，分配到职级了，但是未指定职级 params={}", positionLearnId, message.getParams());
                return;
            }
            gradeId = (String) message.getParams().get(CultivateMqDTO.GRADE_ID);
            courseList = ftbCultivatePositionCourseService.listByPostLearnIdAndGradeId(positionLearnId, gradeId, courseId);
            positionSetting = ftbCultivatePositionSettingService.listByPostLearnIdAndGradeId(positionLearnId, gradeId);
        }
        if (CollUtil.isEmpty(courseList)) {
            log.error("dealPositionCourse positionLearnId={}，courseId={},未查询到课程", positionLearnId, courseId);
            return;
        }
        List<FtbCultivatePositionLog> logList = queryCompletePositionList(userId, positionLearnId, postId, gradeId, position);
        if (CollUtil.isNotEmpty(logList)) {
            log.error("dealPositionCourse positionLearnId={}，courseId={},userId={},postId={},gradeId={},用户已学习完成",
                    positionLearnId, courseId, userId, postId, gradeId);
            return;
        }
        //检查课程是否学习完成
        if (!checkCourseIsComplete(courseList.stream().map(FtbCultivatePositionCourseWithNameVo::getCourseId).collect(Collectors.toList()), userId)) {
            return;
        }

        // 查询考试信息 - 使用新封装的方法
        List<FtbCultivatePositionCourseExam> exams = ftbCultivatePositionCourseExamService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
        List<String> examIds = exams.stream().map(FtbCultivatePositionCourseExam::getExamId).distinct().collect(Collectors.toList());

        // 查询鉴定信息 - 使用新封装的方法
        List<FtbCultivatePositionCourseIdentity> identities = ftbCultivatePositionCourseIdentityService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
        List<String> identityIds = identities.stream().map(FtbCultivatePositionCourseIdentity::getIdentityId).distinct().collect(Collectors.toList());

        // 查询练习信息 - 使用新封装的方法
        List<FtbCultivatePositionCoursePractice> practices = ftbCultivatePositionCoursePracticeService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
        List<String> practiceIds = practices.stream().map(FtbCultivatePositionCoursePractice::getBusinessId).distinct().collect(Collectors.toList());
        Map<String, FtbCultivatePositionCoursePractice> practiceMap = new HashMap<>();
        if (CollUtil.isNotEmpty(practices)) {
            for (FtbCultivatePositionCoursePractice practice : practices) {
                practiceMap.put(practice.getBusinessId(), practice);
            }
        }
        // 查询证书信息 - 使用新封装的方法
        List<FtbCultivatePositionCourseCertificate> certificates = ftbCultivatePositionCourseCertificateService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
        List<String> certificateIds = certificates.stream().map(FtbCultivatePositionCourseCertificate::getCertificateId).distinct().collect(Collectors.toList());

        // 批量查询用户的考试、鉴定、证书、技能完成情况
        Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, examIds);
        Map<String, CultivateIdentifyApply> userIdentificationStatusMap = v2CultivateBatchQueryService.batchQueryUserIdentificationStatus(userId, identityIds, 2, positionLearnId);
//        Map<String, FtbCertificateUserEntity> userCertificateStatusMap = v2CultivateBatchQueryService.batchQueryUserCertificateStatus(userId, certificateIds);
        Map<String, List<String>> userSkillStatusMap = v2CultivateBatchQueryService.batchQueryUserSkillStatus(userId, practiceIds);

        Integer qualified = 0; //试合格和练习满足才能完成鉴定【0-否 1-是】
        if (positionSetting != null) {
            qualified = positionSetting.getQualified();
        }

        // 检查考试、技能和鉴定状态
        PositionStatusResultVo positionStatusResult = evaluatePositionStatus(userId, positionLearnId, examIds, practiceIds, identityIds,
                qualified, userExamStatusMap, userIdentificationStatusMap, practiceMap, userSkillStatusMap, courseId, gradeId, tenantId);

        handlePositionCourseCompletion(userId, positionLearnId, postId, gradeId, courseId, certificateIds, tenantId,
                positionStatusResult);

        checkAndCompletePosition(userId, positionLearnId, postId, gradeId, tenantId);

        // 查询用户所在的学习地图
        List<MyCultivatePromotionListVo> list = ftbCultivatePromotionUserService.queryMyAllPromotionList(userId);
        if (CollUtil.isNotEmpty(list)) {
            List<String> promotionIds = list.stream().map(MyCultivatePromotionListVo::getId).collect(Collectors.toList());
            Map<String, List<FtbCultivatePromotionPostNew>> promotionPostMap = batchQueryPositionsByPromotionIds(promotionIds);
            checkPromotionComplete(list, promotionPostMap, userId, tenantId);
        }
    }

    /**
     * 查询用户对岗位学习是否完成
     *
     * @param userId          用户ID
     * @param positionLearnId 岗位学习ID
     * @param postId          岗位id
     * @param gradeId         职级id
     */
    private void checkAndCompletePosition(String userId, String positionLearnId, String postId, String gradeId, String tenantId) {

        boolean isComplete = ftbCultivatePositionLogService.selectIsCompletePosition(userId, positionLearnId, postId, gradeId, tenantId);
        if (isComplete) {
            return;
        }
        //查询用户已经完成的所有课程id
        List<String> completeCourseIds = v2CultivateBatchQueryService.getUserCompletedCourseIds(userId);
        if (CollUtil.isEmpty(completeCourseIds)) {
            return;
        }

        List<FtbCultivatePositionCourse> courseList = ftbCultivatePositionCourseService.listAllCourseByPostLearnId(positionLearnId, postId, gradeId, 0);
        if (CollUtil.isEmpty(courseList)) {
            return;
        }

        List<String> courseIds = courseList.stream().map(FtbCultivatePositionCourse::getCourseId).collect(Collectors.toList());
        List<CultivatePositionCourseLogEntity> positionCourseLogEntityList = ftbCultivatePositionLogService.queryByUserIdAndPostLearnId(userId, positionLearnId);
        if (CollUtil.isEmpty(positionCourseLogEntityList)) {
            return;
        }
        Map<String, CultivatePositionCourseLogEntity> positionCourseLogEntityMap = new HashMap<>();
        for (CultivatePositionCourseLogEntity positionCourseLogEntity : positionCourseLogEntityList) {
            positionCourseLogEntityMap.put(positionCourseLogEntity.getCourseId(), positionCourseLogEntity);
        }
        // 判断需要完成的课程是否已经全部完成（已完成课程包含所有应完成课程）
        if (CollUtil.isNotEmpty(courseIds) && new HashSet<>(completeCourseIds).containsAll(courseIds)) {
            for (String courseId : courseIds) {
                CultivatePositionCourseLogEntity courseLogEntity = positionCourseLogEntityMap.get(courseId);
                if (courseLogEntity == null) {
                    return;
                }
                if (!courseLogEntity.getState().equals(2)) {
                    return;
                }
                // 检查考试状态：如果有考试(hasExam=2)，则考试状态不能是待考试(0)、待批阅(1)或已逾期(2)
                if (courseLogEntity.getHasExam().equals(2)) {
                    Integer examStatus = courseLogEntity.getUserExamStatus();
                    if (examStatus == null || examStatus.equals(0) || examStatus.equals(1) || examStatus.equals(2)) {
                        return;
                    }
                }
                // 检查鉴定状态：如果有鉴定(hasIdentity=2)，则鉴定状态不能是待鉴定(-1)
                if (courseLogEntity.getHasIdentity().equals(2)) {
                    Integer identifyStatus = courseLogEntity.getUserIdentifyStatus();
                    if (identifyStatus == null || identifyStatus.equals(-1)) {
                        return;
                    }
                }
            }


            ftbCultivatePositionLogService.completePosition(userId, positionLearnId, postId, gradeId, tenantId);
        }
    }

    /**
     * 评估岗位学习状态
     */
    public PositionStatusResultVo evaluatePositionStatus(String userId, String positionLearnId, List<String> examIds, List<String> practiceIds,
                                                         List<String> identityIds,
                                                         Integer qualified,
                                                         Map<String, FtbCultivateExamUser> userExamStatusMap,
                                                         Map<String, CultivateIdentifyApply> userIdentificationStatusMap,
                                                         Map<String, FtbCultivatePositionCoursePractice> practiceMap,
                                                         Map<String, List<String>> userSkillStatusMap,
                                                         String courseId,
                                                         String gradeId,
                                                         String tenantId
    ) {
        boolean isExam = true;//false-未完成  true-已完成
        boolean isPractice = true;//false-未完成  true-已完成
        PositionStatusResultVo resultVo = new PositionStatusResultVo();

        // 根据是否有考试设置hasExam字段
        Integer hasExam = CollUtil.isNotEmpty(examIds) ? 2 : 1;

        // 根据是否有鉴定设置hasIdentity字段
        Integer hasIdentity = CollUtil.isNotEmpty(identityIds) ? 2 : 1;

        // 检查考试状态
        if (CollUtil.isNotEmpty(examIds)) {
            isExam = checkExamStatus(userId, positionLearnId, examIds, qualified, userExamStatusMap, courseId, gradeId, hasIdentity, tenantId);
        }

        // 检查技能状态
        if (CollUtil.isNotEmpty(practiceIds)) {
            isPractice = checkPracticeStatus(practiceIds, practiceMap, userSkillStatusMap, qualified);
        }

        // 检查鉴定状态
        if (CollUtil.isNotEmpty(identityIds)) {
            resultVo = checkIdentificationStatus(userId, positionLearnId, identityIds, qualified,
                    isExam, isPractice, userIdentificationStatusMap, courseId, gradeId, tenantId);
        } else {
            resultVo.setIsIdentification(true);
            resultVo.setFinishIdentification(true);
        }

        // 更新hasExam和hasIdentity字段
        updateHasExamAndIdentity(positionLearnId, userId, courseId, hasExam, hasIdentity, gradeId);
        return new PositionStatusResultVo(isExam, isPractice, resultVo.getIsIdentification(), resultVo.getFinishIdentification());
    }

    /**
     * 检查考试状态
     */
    public boolean checkExamStatus(String userId, String positionLearnId, List<String> examIds, Integer qualified,
                                   Map<String, FtbCultivateExamUser> userExamStatusMap, String courseId, String gradeId, Integer hasIdentity, String tenantId) {
        CultivatePositionCourseLogEntity courseLogEntity = ftbCultivatePositionLogService.queryIsTriggerExam(positionLearnId, userId, courseId, gradeId);
        if (courseLogEntity != null && StringUtils.isNotEmpty(courseLogEntity.getUserExamId())) {
            // 有考试记录时，检查考试状态
            Integer examStatus = courseLogEntity.getUserExamStatus();

            // 如果有待批阅(1)、待考试(0)或已逾期(2)状态，则认为考试未完成
            if (examStatus.equals(0) || examStatus.equals(1) || examStatus.equals(2)) {
                return false;
            }

            // 试合格和练习满足才能完成鉴定【0-否 1-是】
            if (qualified == 1 && hasIdentity == 2) {
                // 需要考试合格或优秀才能触发鉴定
                return examStatus.equals(3) || examStatus.equals(5);
            } else {
                // 不需要鉴定或不需要合格，只要考试有结果即可（合格、不合格、优秀）
                return examStatus.equals(3) || examStatus.equals(4) || examStatus.equals(5);
            }
        }

        // 没有考试记录，查询或创建考试
        FtbCultivateExamUser ftbCultivateExamUser = userExamStatusMap.get(examIds.get(0));
        if (ftbCultivateExamUser != null) {
            ftbCultivatePositionLogService.recordUserExamId(positionLearnId, userId, courseId, gradeId, ftbCultivateExamUser);
            Integer status = ftbCultivateExamUser.getStatus();

            // 如果有待批阅(1)、待考试(0)或已逾期(2)状态，则认为考试未完成
            if (status.equals(0) || status.equals(1) || status.equals(2)) {
                return false;
            }

            if (hasIdentity == 2) {
                // 需要鉴定时，必须考试合格或优秀
                return status.equals(3) || status.equals(5);
            } else {
                // 不需要鉴定时，合格、不合格、优秀都可以
                return status.equals(3) || status.equals(4) || status.equals(5);
            }
        }

        // 触发考试
        ftbCultivateExamUser = triggerExam(userId, examIds.get(0), 2, positionLearnId, tenantId);
        ftbCultivatePositionLogService.recordUserExamId(positionLearnId, userId, courseId, gradeId, ftbCultivateExamUser);
        return false;
    }

    public String checkExamStatusReturnUserExamId(String userId, String positionLearnId, List<String> examIds,
                                                  Map<String, FtbCultivateExamUser> userExamStatusMap, String courseId, String gradeId, String tenantId) {
        CultivatePositionCourseLogEntity courseLogEntity = ftbCultivatePositionLogService.queryIsTriggerExam(positionLearnId, userId, courseId, gradeId);
        if (courseLogEntity != null && StringUtils.isNotEmpty(courseLogEntity.getUserExamId())) {
            return courseLogEntity.getUserExamId();
        }
        FtbCultivateExamUser ftbCultivateExamUser = userExamStatusMap.get(examIds.get(0));
        if (ftbCultivateExamUser != null) {
            ftbCultivatePositionLogService.recordUserExamId(positionLearnId, userId, courseId, gradeId, ftbCultivateExamUser);
            return ftbCultivateExamUser.getId();
        }
        ftbCultivateExamUser = triggerExam(userId, examIds.get(0), 2, positionLearnId, tenantId);
        ftbCultivatePositionLogService.recordUserExamId(positionLearnId, userId, courseId, gradeId, ftbCultivateExamUser);
        return ftbCultivateExamUser.getId();
    }

    /**
     * 检查技能状态
     */
    private boolean checkPracticeStatus(List<String> practiceIds,
                                        Map<String, FtbCultivatePositionCoursePractice> practiceMap,
                                        Map<String, List<String>> userSkillStatusMap,
                                        Integer qualified
    ) {
        for (String practiceId : practiceIds) {
            FtbCultivatePositionCoursePractice ftbCultivatePositionCoursePractice = practiceMap.get(practiceId);
            List<String> count = userSkillStatusMap.get(practiceId);
            if (qualified == 1 && (ftbCultivatePositionCoursePractice == null || count == null || count.size() < ftbCultivatePositionCoursePractice.getNum())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 检查鉴定状态颁发证书
     */
    private PositionStatusResultVo checkIdentificationStatus(String userId, String positionLearnId, List<String> identityIds,
                                                             Integer qualified, boolean isExam, boolean isPractice,
                                                             Map<String, CultivateIdentifyApply> userIdentificationStatusMap,
                                                             String courseId, String gradeId,
                                                             String tenantId
    ) {
        //试合格和练习满足才能完成鉴定【0-否 1-是】
        if (qualified.equals(1)) {
            // 需要考试和练习都完成才能进行鉴定
            if (isExam && isPractice) {
                return checkIdentificationWithQualification(userId, positionLearnId, identityIds, userIdentificationStatusMap, courseId, gradeId, qualified, tenantId);
            }
            return new PositionStatusResultVo() {{
                setIsIdentification(false);
                setFinishIdentification(false);
            }};
        }
        // 不需要考试和练习完成即可鉴定
        return checkIdentificationWithQualification(userId, positionLearnId, identityIds, userIdentificationStatusMap, courseId, gradeId, qualified, tenantId);

    }

    /**
     * 检查鉴定状态（需要考试和练习完成）
     */
    private PositionStatusResultVo checkIdentificationWithQualification(String userId, String positionLearnId, List<String> identityIds,
                                                                        Map<String, CultivateIdentifyApply> userIdentificationStatusMap,
                                                                        String courseId, String gradeId, Integer qualified, String tenantId) {
        PositionStatusResultVo resultVo = new PositionStatusResultVo();
        CultivatePositionCourseLogEntity courseLogEntity = ftbCultivatePositionLogService.queryIsTriggerExam(positionLearnId, userId, courseId, gradeId);
        if (courseLogEntity != null && StringUtils.isNotEmpty(courseLogEntity.getUserIdentifyId())) {
            // 有鉴定记录时，检查鉴定状态
            Integer identifyStatus = courseLogEntity.getUserIdentifyStatus();

            // -1:待鉴定，认为鉴定未完成
            if (identifyStatus == null || identifyStatus.equals(-1)) {
                resultVo.setIsIdentification(false);
                resultVo.setFinishIdentification(false);
            } else {
                resultVo.setFinishIdentification(true);
                // 鉴定结果为 0-合格，1-优秀，则认为鉴定完成；2-不合格，也认为有结果了
                if (qualified == 0) {
                    resultVo.setIsIdentification(true);
                } else {
                    resultVo.setIsIdentification(!identifyStatus.equals(2));
                }
            }

            return resultVo;
        }

        // 没有鉴定记录，查询或创建鉴定
        CultivateIdentifyApply cultivateIdentifyApply = userIdentificationStatusMap.get(identityIds.get(0));
        if (cultivateIdentifyApply == null) {
            cultivateIdentifyApply = triggerIdentification(userId, identityIds.get(0), 2, positionLearnId, tenantId);
            ftbCultivatePositionLogService.recordUserIdentificationId(positionLearnId, userId, courseId, gradeId, cultivateIdentifyApply);
            resultVo.setIsIdentification(false);
            resultVo.setFinishIdentification(false);
            return resultVo;
        }

        // status: 0-待鉴定, 1-已完成, 2-已撤销
        // result: 0-合格, 1-优秀, 2-不合格
        if (cultivateIdentifyApply.getStatus().equals(0) || cultivateIdentifyApply.getStatus().equals(2)) {
            // 待鉴定或已撤销，认为鉴定未完成
            resultVo.setIsIdentification(false);
            resultVo.setFinishIdentification(false);
            return resultVo;
        }

        // 已完成且结果不是不合格，则认为鉴定完成
        if (qualified == 0) {
            resultVo.setIsIdentification(true);
        } else {
            resultVo.setIsIdentification(!cultivateIdentifyApply.getResult().equals(2));
        }
        resultVo.setFinishIdentification(true);
        return resultVo;
    }

    /**
     * 更新是否有考试和是否有鉴定字段
     *
     * @param positionLearnId 岗位学习ID
     * @param userId          用户ID
     * @param courseId        课程ID
     * @param hasExam         是否有考试 1-没有 2-有
     * @param hasIdentity     是否有鉴定 1-没有 2-有
     */
    private void updateHasExamAndIdentity(String positionLearnId, String userId, String courseId, Integer hasExam, Integer hasIdentity, String gradeId) {
        LambdaUpdateWrapper<CultivatePositionCourseLogEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(CultivatePositionCourseLogEntity::getPostLearnId, positionLearnId)
                .eq(CultivatePositionCourseLogEntity::getUserId, userId)
                .eq(CultivatePositionCourseLogEntity::getCourseId, courseId)
                .eq(StringUtils.isNotEmpty(gradeId), CultivatePositionCourseLogEntity::getGradeId, gradeId)
                .eq(CultivatePositionCourseLogEntity::getEnabledMark, 0)
                .set(CultivatePositionCourseLogEntity::getHasExam, hasExam)
                .set(CultivatePositionCourseLogEntity::getHasIdentity, hasIdentity);
        cultivatePositionCourseLogService.update(null, updateWrapper);
    }

    /**
     * 处理岗位学习完成逻辑（证书和日志记录）
     */
    private void handlePositionCourseCompletion(String userId, String positionLearnId, String postId, String gradeId, String courseId,
                                                List<String> certificateIds, String tenantId,
                                                PositionStatusResultVo positionStatusResult) {
        //颁发证书
        if (positionStatusResult.getIsExam() && positionStatusResult.getIsPractice() && positionStatusResult.getIsIdentification()) {
            if (CollUtil.isNotEmpty(certificateIds)) {
                if (!checkIsTriggerPositionCertificate(userId, certificateIds.get(0), positionLearnId, postId, gradeId, courseId)) {
                    triggerCertificate(userId, certificateIds.get(0), tenantId);
                    recordTriggerPositionCertificate(userId, certificateIds.get(0), positionLearnId, postId, gradeId, courseId);
                }
            }
        }
        //鉴定完成 进入下一阶段
        if (positionStatusResult.getIsExam() && positionStatusResult.getIsPractice() && positionStatusResult.getFinishIdentification()) {
            ftbCultivatePositionLogService.completePositionCourse(userId, positionLearnId, postId, gradeId, courseId);
        }
    }


    /**
     * 通用课程学习
     *
     * @param message 培训信息
     */
    @Override
    @Transactional
    public void dealCommonCourseStudy(CultivateMqDTO message) {

        String userId = message.getUserId();
        String courseId = message.getBusinessId();
        String tenantId = message.getTenantId();

        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未null，examId={}, userId={}", userId);
            return;
        }

        FtbCultivateCourse course = ftbCultivateCourseService.getById(courseId);
        if (course == null || course.getEnableMark() == 1 || course.getIsGroundIng().equals(0)) {
            log.warn("dealCommonCourseStudy方法接收到的message为null");
            return;
        }
        if (course.getNeedExamAndIdentify().equals(0)) {
            return;
        }
        if (StringUtils.isNotEmpty(course.getExamId())) {
            Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, List.of(course.getExamId()));
            //触发考试
            FtbCultivateExamUser ftbCultivateExamUser = userExamStatusMap.get(course.getExamId());
            if (ftbCultivateExamUser == null) {
                //触发考试
                triggerExam(userId, course.getExamId(), 1, courseId, tenantId);
            }
        }
        if (StringUtils.isNotEmpty(course.getIdentifyId())) {
            Map<String, CultivateIdentifyApply> userIdentificationStatusMap = v2CultivateBatchQueryService.batchQueryUserIdentificationStatus(userId, List.of(course.getIdentifyId()), 1, courseId);
            CultivateIdentifyApply cultivateIdentifyApply = userIdentificationStatusMap.get(course.getIdentifyId());
            if (cultivateIdentifyApply == null) {
                //触发鉴定  userid + identifyId + positionId
                triggerIdentification(userId, course.getIdentifyId(), 1, courseId, tenantId);
            }
        }

    }

    /**
     * 岗位考试学习
     *
     * @param message 培训信息
     */
    @Override
    public void dealPositionExamStudy(CultivateMqDTO message) {
        String userId = message.getUserId();
        String examId = message.getBusinessId();
        String tenantId = message.getTenantId();
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未 null，examId={}, userId={}", examId, userId);
            return;
        }
        if (StringUtils.isEmpty(examId) || StringUtils.isEmpty(userId)) {
            log.error("dealPositionExamStudy 参数不完整，examId={}, userId={}", examId, userId);
            return;
        }
        recodePositionCourseExam(userId, examId, message.getParams(), message.getStatus());

        // 获取需要检查的岗位和职级列表
        CheckPostAndGradeResult result = buildCheckPostAndGradeList(userPrimaryBoundOne, userId);
        if (CollUtil.isEmpty(result.getCheckPostAndGrade())) {
            return;
        }

        for (V2CultivatePostAndGradeVoExt itemVo : result.getCheckPostAndGrade()) {
            this.selfProxy.dealPositionExamStudyItem(userPrimaryBoundOne, examId, itemVo, tenantId);
        }

        //判断学习地图是否完成并记录
        checkPromotionComplete(result.getList(), result.getPromotionPostMap(), userId, tenantId);
    }


    public String preCommonCourseStudy(String userId, String courseId, String tenantId) {
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未null，examId={}, userId={}", userId);
            return "";
        }
        FtbCultivateCourse course = ftbCultivateCourseService.getById(courseId);
        if (course == null || course.getEnableMark() == 1 || course.getIsGroundIng().equals(0)) {
            log.warn("dealCommonCourseStudy方法接收到的message为null");
            return "";
        }
        if (course.getNeedExamAndIdentify().equals(0)) {
            return "";
        }
        if (StringUtils.isNotEmpty(course.getExamId())) {
            Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, List.of(course.getExamId()));
            //触发考试
            FtbCultivateExamUser ftbCultivateExamUser = userExamStatusMap.get(course.getExamId());
            if (ftbCultivateExamUser == null) {
                //触发考试
                ftbCultivateExamUser = triggerExam(userId, course.getExamId(), 1, courseId, tenantId);
            }
            if (ftbCultivateExamUser != null) {
                return ftbCultivateExamUser.getId();
            }

        }
        return "";
    }

    private void recodePositionCourseExam(String userId, String examId, Map<String, Object> params, Integer status) {
        if (params == null) {
            return;
        }
        if (params.get("userExamId") == null || params.get("userExamId").equals("")) {
            return;
        }
        String userExamId = (String) params.get("userExamId");
        ftbCultivatePositionLogService.recodePositionCourseExam(userId, examId, userExamId, status);
    }


    /**
     * 岗位学习
     *
     * @param message 培训信息
     */
    @Override
    public void dealPositionReCheckStudy(CultivateMqDTO message) {
        String userId = message.getUserId();
        String tenantId = message.getTenantId();
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("dealPositionReCheckStudy 用户查询未 null，userId={},tenantId={}", userId, tenantId);
            return;
        }
        if (StringUtils.isEmpty(tenantId) || StringUtils.isEmpty(userId)) {
            log.error("dealPositionReCheckStudy 参数补全，userId={},tenantId={}", userId, tenantId);
            return;
        }

        // 获取需要检查的岗位和职级列表
        CheckPostAndGradeResult result = buildCheckPostAndGradeList(userPrimaryBoundOne, userId);
        if (CollUtil.isEmpty(result.getCheckPostAndGrade())) {
            return;
        }

        for (V2CultivatePostAndGradeVoExt itemVo : result.getCheckPostAndGrade()) {
            this.selfProxy.dealPositionReCheckStudyItem(userPrimaryBoundOne, itemVo, tenantId);
        }

        //判断学习地图是否完成并记录
        checkPromotionComplete(result.getList(), result.getPromotionPostMap(), userId, tenantId);


    }


    /**
     * 岗位鉴定学习
     *
     * @param message 培训信息
     */
    @Override
    public void dealPositionIdentityStudy(CultivateMqDTO message) {
        String userId = message.getUserId();
        String identityId = message.getBusinessId();
        String tenantId = message.getTenantId();

        if (StringUtils.isEmpty(identityId) || StringUtils.isEmpty(userId)) {
            log.error("dealPositionIdentityStudy参数不完整，identityId={}, userId={}", identityId, userId);
            return;
        }

        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未null，identityId={}, userId={}", identityId, userId);
            return;
        }
        recodePositionIdentityLog(userId, identityId, message);

        // 查询需要鉴定的岗位和职级
        CheckPostAndGradeResult result = buildCheckPostAndGradeList(userPrimaryBoundOne, userId);
        if (CollUtil.isEmpty(result.getCheckPostAndGrade())) {
            return;
        }
        for (V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVoExt : result.getCheckPostAndGrade()) {
            this.selfProxy.dealPositionIdentityStudyItem(userPrimaryBoundOne, identityId, v2CultivatePostAndGradeVoExt, tenantId);
        }


        //判断学习地图是否完成并记录
        checkPromotionComplete(result.getList(), result.getPromotionPostMap(), userId, tenantId);
    }

    private void recodePositionIdentityLog(String userId, String identityId, CultivateMqDTO message) {

        Map<String, Object> params = message.getParams();
        if (params == null) {
            return;
        }
        String userIdentifyId = (String) params.get("userIdentifyId");
        Integer userIdentifyStatus = (Integer) params.get("userIdentifyStatus");
        Integer status = message.getStatus();
        ftbCultivatePositionLogService.recodePositionCourseIdentify(userId, identityId, userIdentifyId, status, userIdentifyStatus);
    }

    /**
     * 岗位技能学习
     *
     * @param message 培训信息
     */
    @Override
    public void dealPositionPracticeStudy(CultivateMqDTO message) {

        String userId = message.getUserId();
        String practiceId = message.getBusinessId();
        String tenantId = message.getTenantId();

        if (StringUtils.isEmpty(practiceId) || StringUtils.isEmpty(userId)) {
            log.error("dealPositionExamStudy参数不完整，practiceId={}, userId={}", practiceId, userId);
            return;
        }

        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未null，practiceId={}, userId={}", practiceId, userId);
            return;
        }

        // 查询需要练习的岗位和职级
        CheckPostAndGradeResult result = buildCheckPostAndGradeList(userPrimaryBoundOne, userId);
        if (CollUtil.isEmpty(result.getCheckPostAndGrade())) {
            return;
        }
        for (V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVoExt : result.getCheckPostAndGrade()) {
            this.selfProxy.dealPositionPracticeStudyItem(userPrimaryBoundOne, practiceId, v2CultivatePostAndGradeVoExt, tenantId);
        }

        //判断学习地图是否完成并记录
        checkPromotionComplete(result.getList(), result.getPromotionPostMap(), userId, tenantId);
    }

    /**
     * 构建需要检查的岗位和职级列表
     *
     * @param userPrimaryBoundOne 用户主要绑定信息
     * @param userId              用户 ID
     * @return 检查结果，包含岗位职级列表、学习地图和岗位映射
     */
    private CheckPostAndGradeResult buildCheckPostAndGradeList(UserBoundVO userPrimaryBoundOne, String userId) {
        // 查询所有的岗位学习
        List<V2CultivatePostAndGradeVoExt> v2CultivatePostAndGradeVos = queryAllPositionAndGrade();
        if (CollUtil.isEmpty(v2CultivatePostAndGradeVos)) {
            return new CheckPostAndGradeResult(new ArrayList<>(), null, null);
        }
        Map<String, V2CultivatePostAndGradeVoExt> v2CultivatePostAndGradeVosMap = convertV2CultivatePostAndGradeVoMap(v2CultivatePostAndGradeVos);
        List<V2CultivatePostAndGradeVoExt> checkPostAndGrade = new ArrayList<>();

        // 查询用户所在的学习地图
        List<MyCultivatePromotionListVo> list = ftbCultivatePromotionUserService.queryMyAllPromotionList(userId);
        Map<String, List<FtbCultivatePromotionPostNew>> promotionPostMap = null;

        if (CollUtil.isNotEmpty(list)) {
            List<String> promotionIds = list.stream().map(MyCultivatePromotionListVo::getId).collect(Collectors.toList());

            // 用户所在阶段
            List<BatchCommonCountDto> currentPhaseList = ftbCultivatePromotionMemberNewService.queryMyCurrentPhase(userId, promotionIds);
            Map<String, BatchCommonCountDto> currentPhaseMap = new HashMap<>();
            if (CollUtil.isNotEmpty(currentPhaseList)) {
                currentPhaseMap = currentPhaseList.stream().collect(Collectors.toMap(BatchCommonCountDto::getSelectKey, v -> v));
            }
            promotionPostMap = batchQueryPositionsByPromotionIds(promotionIds);

            for (MyCultivatePromotionListVo item : list) {
                List<FtbCultivatePromotionPostNew> promotionPostNews = promotionPostMap.get(item.getId());
                if (CollUtil.isEmpty(promotionPostNews)) {
                    continue;
                }

                Integer currLevel;
                BatchCommonCountDto currentPhase = currentPhaseMap.get(item.getId());
                if (currentPhase != null) {
                    currLevel = currentPhase.getNum();
                } else {
                    currLevel = 1;
                }

                Map<Integer, List<FtbCultivatePromotionPostNew>> currentPhasePostMap = groupAndSortByLevel(promotionPostNews);

                for (Map.Entry<Integer, List<FtbCultivatePromotionPostNew>> entry : currentPhasePostMap.entrySet()) {
                    if (currLevel > entry.getKey()) {
                        break;
                    }
                    List<FtbCultivatePromotionPostNew> postNewList = entry.getValue();

                    for (FtbCultivatePromotionPostNew postNew : postNewList) {
                        V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVo = v2CultivatePostAndGradeVosMap.get(postNew.getPostId() + "-" + postNew.getGradeId());
                        if (v2CultivatePostAndGradeVo == null) {
                            continue;
                        }
                        checkPostAndGrade.add(v2CultivatePostAndGradeVo);
                    }
                }
            }
        }

        // 添加用户当前岗位
        V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVo = queryUserSelfPosition(userPrimaryBoundOne);
        if (v2CultivatePostAndGradeVo != null) {
            checkPostAndGrade.add(v2CultivatePostAndGradeVo);
        }

        return new CheckPostAndGradeResult(checkPostAndGrade, list, promotionPostMap);
    }


    private void checkPromotionComplete(List<MyCultivatePromotionListVo> list, Map<String, List<FtbCultivatePromotionPostNew>> promotionPostMap, String userId, String tenantId) {
        if (CollUtil.isEmpty(list) || CollUtil.isEmpty(promotionPostMap)) {
            return;
        }
        //查找已经完成的岗位学习
        List<FtbCultivatePositionLog> myCompletePositionList = ftbCultivatePositionLogService.queryMyCompletePosition(userId);
        List<FtbCultivatePromotionMemberNew> memberList = ftbCultivatePromotionMemberNewService.queryMyAllSelectPosition(userId);
        List<FtbCultivatePromotionLog> completePromotionList = ftbCultivatePromotionLogService.queryMyCompletePromotion(userId, 2);
        List<String> completePromotionUserList = ftbCultivatePromotionUserService.queryMyCompletePromotion(userId);
        List<CultivatePositionCourseLogEntity> positionCourseLogEntityList = cultivatePositionCourseLogService.queryMyAllCompletePositionCourse(userId);
        Map<String, CultivatePositionCourseLogEntity> positionCourseLogEntityMap = new HashMap<>();
        if (CollUtil.isNotEmpty(positionCourseLogEntityList)) {
            for (CultivatePositionCourseLogEntity courseLogEntity : positionCourseLogEntityList) {
                if (StringUtils.isNotEmpty(courseLogEntity.getGradeId())) {
                    positionCourseLogEntityMap.put(courseLogEntity.getPostId() + "-" + courseLogEntity.getGradeId(), courseLogEntity);
                } else {
                    positionCourseLogEntityMap.put(courseLogEntity.getPostId(), courseLogEntity);
                }
            }
        }
        if (CollUtil.isEmpty(memberList)) {
            return;
        }
        List<String> completePromotion = new ArrayList<>();
        for (FtbCultivatePromotionLog ftbCultivatePromotionLog : completePromotionList) {
            completePromotion.add(ftbCultivatePromotionLog.getPromotionId() + "-" + ftbCultivatePromotionLog.getLevel());
        }
        //按照 promotionId 分组
        Map<String, List<FtbCultivatePromotionMemberNew>> memberMap = memberList.stream().collect(Collectors.groupingBy(FtbCultivatePromotionMemberNew::getPromotionId));
//        按照岗位分组
        List<String> completePostAndGrade = new ArrayList<>();
        for (FtbCultivatePositionLog ftbCultivatePositionLog : myCompletePositionList) {
            if (StringUtils.isEmpty(ftbCultivatePositionLog.getGradeId())) {
                completePostAndGrade.add(ftbCultivatePositionLog.getPostId());
            } else {
                completePostAndGrade.add(ftbCultivatePositionLog.getPostId() + "-" + ftbCultivatePositionLog.getGradeId());
            }

        }
        for (MyCultivatePromotionListVo promotionVo : list) {
            if (completePromotionUserList.contains(promotionVo.getId())) {
                continue;
            }
            List<FtbCultivatePromotionPostNew> promotionPostNews = promotionPostMap.get(promotionVo.getId());
            if (CollUtil.isEmpty(promotionPostNews)) {
                continue;
            }
            Map<Integer, List<FtbCultivatePromotionPostNew>> currentPhasePostMap = groupAndSortByLevel(promotionPostNews);
            Integer maxCompleteLevel = 0;
            for (Map.Entry<Integer, List<FtbCultivatePromotionPostNew>> entry : currentPhasePostMap.entrySet()) {
                Integer level = entry.getKey();
                List<FtbCultivatePromotionPostNew> postNewList = entry.getValue();
                if (CollUtil.isEmpty(postNewList)) {
                    continue;
                }
                List<FtbCultivatePromotionMemberNew> memberNewList = memberMap.get(promotionVo.getId());
                if (CollUtil.isEmpty(memberNewList)) {
                    continue;
                }
                if (completePromotion.contains(promotionVo.getId() + "-" + level)) {
                    maxCompleteLevel = level;
                    continue;
                }
                //memberNewList按照level分组
                Map<Integer, List<FtbCultivatePromotionMemberNew>> memberNewMap = memberNewList.stream().collect(Collectors.groupingBy(FtbCultivatePromotionMemberNew::getCurrentLearningStage));

                List<FtbCultivatePromotionMemberNew> currMemberLists = memberNewMap.get(level);
                if (CollUtil.isEmpty(currMemberLists)) {
                    continue;
                }
                Map<String, FtbCultivatePromotionPostNew> promotionPostNewMap = postNewList.stream().collect(Collectors.toMap(FtbCultivatePromotionPostNew::getId, v -> v));

                boolean isCompleteLevel = true;
                for (FtbCultivatePromotionMemberNew memberNew : currMemberLists) {
                    FtbCultivatePromotionPostNew ftbCultivatePromotionPostNew = promotionPostNewMap.get(memberNew.getPromotionPostId());
                    if (ftbCultivatePromotionPostNew == null) {
                        isCompleteLevel = false;
                        break;
                    }
                    String key = ftbCultivatePromotionPostNew.getPostId();
                    if (StringUtils.isNotEmpty(ftbCultivatePromotionPostNew.getGradeId())) {
                        key = ftbCultivatePromotionPostNew.getPostId() + "-" + ftbCultivatePromotionPostNew.getGradeId();
                    }
                    if (!completePostAndGrade.contains(key)) {
                        isCompleteLevel = false;
                        break;
                    }
                    if (promotionVo.getLearningMapSetting().equals(1)) {
                        CultivatePositionCourseLogEntity courseLogEntity = positionCourseLogEntityMap.get(key);
                        if (courseLogEntity != null) {
                            if (courseLogEntity.getHasExam().equals(2) && (courseLogEntity.getUserExamStatus() != 3 && courseLogEntity.getUserExamStatus() != 5)) {
                                isCompleteLevel = false;
                                break;
                            }

                            if (courseLogEntity.getHasIdentity().equals(2) && (courseLogEntity.getUserIdentifyStatus() != 0 && courseLogEntity.getUserIdentifyStatus() != 1)) {
                                isCompleteLevel = false;
                                break;
                            }
                        }

                    } else {
                        CultivatePositionCourseLogEntity courseLogEntity = positionCourseLogEntityMap.get(key);
                        if (courseLogEntity != null) {
                            if (courseLogEntity.getHasExam().equals(2) && (courseLogEntity.getUserExamStatus() != 3 && courseLogEntity.getUserExamStatus() != 4 && courseLogEntity.getUserExamStatus() != 5)) {
                                isCompleteLevel = false;
                                break;
                            }

                            if (courseLogEntity.getHasIdentity().equals(2) && (courseLogEntity.getUserIdentifyStatus() == -1)) {
                                isCompleteLevel = false;
                                break;
                            }
                        }

                    }
                }
                if (isCompleteLevel) {
                    //完成学习
                    ftbCultivatePromotionLogService.completePromotionLevel(userId, promotionVo.getId(), level, tenantId);
                    maxCompleteLevel = level;
                }
            }
            Set<Integer> levels = currentPhasePostMap.keySet();
            if (maxCompleteLevel >= Collections.max(levels)) {
                ftbCultivatePromotionUserService.completePromotion(userId, promotionVo.getId(), tenantId);
            }
        }
    }


    @Override
    public void dealPositionIdentityStudyItem(UserBoundVO userBoundVO, String identityId, V2CultivatePostAndGradeVoExt itemVo, String tenantId) {
        String userId = userBoundVO.getId();
        String positionLearnId = itemVo.getId();
        String postId = itemVo.getPostId();
        String gradeId = itemVo.getGradeId();
        FtbCultivatePositionSetting positionSetting = itemVo.getSetting();
        List<FtbCultivatePositionCourse> courseList = ftbCultivatePositionCourseService.listByPostLearnIdAndIdentityId(positionLearnId, gradeId, identityId);
        if (CollUtil.isEmpty(courseList)) {
            log.error("dealPositionPracticeStudyItem，positionLearnId={},gradeId={}, identityId={}, userId={}",
                    positionLearnId, gradeId, identityId, userId);
            return;
        }
        FtbCultivatePosition position = ftbCultivatePositionService.getById(positionLearnId);
        if (position == null || position.getEnabledMark() == 1) {
            log.error("dealRealPositionExamStudy未查询到岗位信息，positionLearnId={},postId={},userId={},", positionLearnId, postId, userId);
            return;
        }
        List<FtbCultivatePositionLog> logList = queryCompletePositionList(userId, positionLearnId, postId, gradeId, position);
        if (CollUtil.isNotEmpty(logList)) {
            log.error("dealPositionIdentityStudyItem positionLearnId={}，identityId={},userId={},postId={},gradeId={},用户已学习完成",
                    positionLearnId, identityId, userId, postId, gradeId);
            return;
        }
        Map<String, jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning> courseLearningMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userId,
                courseList.stream().map(FtbCultivatePositionCourse::getCourseId).collect(Collectors.toList()));

        for (FtbCultivatePositionCourse ftbCultivatePositionCourse : courseList) {
            String courseId = ftbCultivatePositionCourse.getCourseId();
            if (!checkItemCourseIsComplete(courseLearningMap, courseId)) {
                continue;
            }

            // 查询考试信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseExam> exams = ftbCultivatePositionCourseExamService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
            List<String> examIds = exams.stream().map(FtbCultivatePositionCourseExam::getExamId).distinct().collect(Collectors.toList());

            // 查询鉴定信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseIdentity> identities = ftbCultivatePositionCourseIdentityService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
            List<String> identityIds = identities.stream().map(FtbCultivatePositionCourseIdentity::getIdentityId).distinct().collect(Collectors.toList());

            // 查询练习信息 - 使用新封装的方法
            List<FtbCultivatePositionCoursePractice> practices = ftbCultivatePositionCoursePracticeService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
            List<String> practiceIds = practices.stream().map(FtbCultivatePositionCoursePractice::getBusinessId).distinct().collect(Collectors.toList());
            Map<String, FtbCultivatePositionCoursePractice> practiceMap = new HashMap<>();
            if (CollUtil.isNotEmpty(practices)) {
                for (FtbCultivatePositionCoursePractice practice : practices) {
                    practiceMap.put(practice.getBusinessId(), practice);
                }
            }
            // 查询证书信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseCertificate> certificates = ftbCultivatePositionCourseCertificateService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
            List<String> certificateIds = certificates.stream().map(FtbCultivatePositionCourseCertificate::getCertificateId).distinct().collect(Collectors.toList());

            // 批量查询用户的考试、鉴定、证书、技能完成情况
            Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, examIds);
            Map<String, CultivateIdentifyApply> userIdentificationStatusMap = v2CultivateBatchQueryService.batchQueryUserIdentificationStatus(userId, identityIds, 2, positionLearnId);
//        Map<String, FtbCertificateUserEntity> userCertificateStatusMap = v2CultivateBatchQueryService.batchQueryUserCertificateStatus(userId, certificateIds);
            Map<String, List<String>> userSkillStatusMap = v2CultivateBatchQueryService.batchQueryUserSkillStatus(userId, practiceIds);

            Integer qualified = 0; //试合格和练习满足才能完成鉴定【0-否 1-是】
            if (positionSetting != null) {
                qualified = positionSetting.getQualified();
            }

            // 检查考试、技能和鉴定状态
            PositionStatusResultVo positionStatusResult = evaluatePositionStatus(userId, positionLearnId, examIds, practiceIds, identityIds,
                    qualified, userExamStatusMap, userIdentificationStatusMap, practiceMap, userSkillStatusMap, courseId, ftbCultivatePositionCourse.getGradeId(), tenantId);
            boolean isExam = positionStatusResult.getIsExam();
            boolean isPractice = positionStatusResult.getIsPractice();
            boolean isIdentification = positionStatusResult.getIsIdentification();

            handlePositionCourseCompletion(userId, positionLearnId, postId, gradeId, courseId, certificateIds, tenantId,
                    positionStatusResult);
        }

        checkAndCompletePosition(userId, positionLearnId, postId, gradeId, tenantId);

    }

    @Override
    public void dealPositionPracticeStudyItem(UserBoundVO userBoundVO, String practiceId, V2CultivatePostAndGradeVoExt itemVo, String tenantId) {
        String userId = userBoundVO.getId();
        String positionLearnId = itemVo.getId();
        String postId = itemVo.getPostId();
        String gradeId = itemVo.getGradeId();
        FtbCultivatePositionSetting positionSetting = itemVo.getSetting();
        List<FtbCultivatePositionCourse> courseList = ftbCultivatePositionCourseService.listByPostLearnIdAndPracticeId(positionLearnId, gradeId, practiceId);
        if (CollUtil.isEmpty(courseList)) {
            log.error("dealPositionPracticeStudyItem，positionLearnId={},gradeId={}, practiceId={}, userId={}",
                    positionLearnId, gradeId, practiceId, userId);
            return;
        }
        FtbCultivatePosition position = ftbCultivatePositionService.getById(positionLearnId);
        if (position == null || position.getEnabledMark() == 1) {
            log.error("dealPositionPracticeStudyItem未查询到岗位信息，positionLearnId={},postId={},userId={},", positionLearnId, postId, userId);
            return;
        }

        List<FtbCultivatePositionLog> logList = queryCompletePositionList(userId, positionLearnId, postId, gradeId, position);
        if (CollUtil.isNotEmpty(logList)) {
            log.error("dealPositionPracticeStudyItem positionLearnId={}，practiceId={},userId={},postId={},gradeId={},用户已学习完成",
                    positionLearnId, practiceId, userId, postId, gradeId);
            return;
        }
        Map<String, FtbCultivatePositionCourceLearning> courseLearningMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userId,
                courseList.stream().map(FtbCultivatePositionCourse::getCourseId).collect(Collectors.toList()));

        checkAndDoPositionStudy(tenantId, userId, positionLearnId, postId, gradeId, positionSetting, courseList, courseLearningMap);

    }

    @Override
    public void prePositionCourseStudy(String userId, String courseId, String postLearnId, String gradeId, String tenantId) {
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne == null) {
            log.error("用户查询未 null，courseId={}, userId={}", courseId, userId);
            return;
        }
        FtbCultivatePosition position = ftbCultivatePositionService.getById(postLearnId);
        if (position == null) {
            return;
        }
        FtbCultivatePositionSetting positionSetting;

        if (position.getIsConfiguredToGrade().equals(0)) {
            positionSetting = ftbCultivatePositionSettingService.listByPostLearnId(postLearnId);
        } else {
            if (StringUtils.isEmpty(gradeId)) {
                return;
            }
            positionSetting = ftbCultivatePositionSettingService.listByPostLearnIdAndGradeId(postLearnId, gradeId);
        }

        List<V2AllCultivatePositionCourseExam> examList = ftbCultivatePositionCourseExamService.queryAllConfigExamId(List.of(postLearnId), courseId, gradeId);
        if (CollUtil.isEmpty(examList)) {
            return;
        }
        Integer qualified = 0; //试合格和练习满足才能完成鉴定【0-否 1-是】
        if (positionSetting != null) {
            qualified = positionSetting.getQualified();
        }

        Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, examList.stream().map(V2AllCultivatePositionCourseExam::getExamId).collect(Collectors.toList()));
        for (V2AllCultivatePositionCourseExam exam : examList) {
            checkExamStatus(userId, exam.getPostLearnId(), List.of(exam.getExamId()), qualified, userExamStatusMap, courseId, exam.getGradeId(), 1, tenantId);
        }

    }

    private void checkAndDoPositionStudy(String tenantId, String userId, String positionLearnId, String postId, String gradeId, FtbCultivatePositionSetting positionSetting, List<FtbCultivatePositionCourse> courseList, Map<String, FtbCultivatePositionCourceLearning> courseLearningMap) {
        for (FtbCultivatePositionCourse ftbCultivatePositionCourse : courseList) {
            String courseId = ftbCultivatePositionCourse.getCourseId();
            if (!checkItemCourseIsComplete(courseLearningMap, courseId)) {
                continue;
            }

            // 查询考试信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseExam> exams = ftbCultivatePositionCourseExamService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
            List<String> examIds = exams.stream().map(FtbCultivatePositionCourseExam::getExamId).distinct().collect(Collectors.toList());

            // 查询鉴定信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseIdentity> identities = ftbCultivatePositionCourseIdentityService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
            List<String> identityIds = identities.stream().map(FtbCultivatePositionCourseIdentity::getIdentityId).distinct().collect(Collectors.toList());

            // 查询练习信息 - 使用新封装的方法
            List<FtbCultivatePositionCoursePractice> practices = ftbCultivatePositionCoursePracticeService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
            List<String> practiceIds = practices.stream().map(FtbCultivatePositionCoursePractice::getBusinessId).distinct().collect(Collectors.toList());
            Map<String, FtbCultivatePositionCoursePractice> practiceMap = new HashMap<>();
            if (CollUtil.isNotEmpty(practices)) {
                for (FtbCultivatePositionCoursePractice practice : practices) {
                    practiceMap.put(practice.getBusinessId(), practice);
                }
            }
            // 查询证书信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseCertificate> certificates = ftbCultivatePositionCourseCertificateService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
            List<String> certificateIds = certificates.stream().map(FtbCultivatePositionCourseCertificate::getCertificateId).distinct().collect(Collectors.toList());

            // 批量查询用户的考试、鉴定、证书、技能完成情况
            Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, examIds);
            Map<String, CultivateIdentifyApply> userIdentificationStatusMap = v2CultivateBatchQueryService.batchQueryUserIdentificationStatus(userId, identityIds, 2, ftbCultivatePositionCourse.getPostLearnId());
//        Map<String, FtbCertificateUserEntity> userCertificateStatusMap = v2CultivateBatchQueryService.batchQueryUserCertificateStatus(userId, certificateIds);
            Map<String, List<String>> userSkillStatusMap = v2CultivateBatchQueryService.batchQueryUserSkillStatus(userId, practiceIds);

            Integer qualified = 0; //试合格和练习满足才能完成鉴定【0-否 1-是】
            if (positionSetting != null) {
                qualified = positionSetting.getQualified();
            }

            // 检查考试、技能和鉴定状态
            PositionStatusResultVo positionStatusResult = evaluatePositionStatus(userId, positionLearnId, examIds, practiceIds, identityIds,
                    qualified, userExamStatusMap, userIdentificationStatusMap, practiceMap, userSkillStatusMap, courseId, gradeId, tenantId);

            handlePositionCourseCompletion(userId, positionLearnId, postId, gradeId, courseId, certificateIds, tenantId,
                    positionStatusResult);
        }
        checkAndCompletePosition(userId, positionLearnId, postId, gradeId, tenantId);
    }


    @Transactional
    @Override
    public void dealPositionExamStudyItem(UserBoundVO userBoundVO, String examId, V2CultivatePostAndGradeVoExt itemVo, String tenantId) {
        String userId = userBoundVO.getId();
        String positionLearnId = itemVo.getId();
        String postId = itemVo.getPostId();
        String gradeId = itemVo.getGradeId();
        FtbCultivatePositionSetting positionSetting = itemVo.getSetting();
        List<FtbCultivatePositionCourse> courseList = ftbCultivatePositionCourseService.listByPostLearnIdAndExamId(positionLearnId, gradeId, examId);
        if (CollUtil.isEmpty(courseList)) {
            log.error("dealRealPositionExamStudy未查询到课程信息，positionLearnId={},gradeId={}, examId={}, userId={}",
                    positionLearnId, gradeId, examId, userId);
            return;
        }
        FtbCultivatePosition position = ftbCultivatePositionService.getById(positionLearnId);
        if (position == null || position.getEnabledMark() == 1) {
            log.error("dealRealPositionExamStudy未查询到岗位信息，positionLearnId={},postId={},userId={},", positionLearnId, postId, userId);
            return;
        }

        List<FtbCultivatePositionLog> logList = queryCompletePositionList(userId, positionLearnId, postId, gradeId, position);
        if (CollUtil.isNotEmpty(logList)) {
            log.error("dealPositionExamStudyItem positionLearnId={}，examId={},userId={},postId={},gradeId={},用户已学习完成",
                    positionLearnId, examId, userId, postId, gradeId);
            return;
        }
        Map<String, jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning> courseLearningMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userId,
                courseList.stream().map(FtbCultivatePositionCourse::getCourseId).collect(Collectors.toList()));

        checkAndDoPositionStudy(tenantId, userId, positionLearnId, postId, gradeId, positionSetting, courseList, courseLearningMap);

    }

    private List<FtbCultivatePositionLog> queryCompletePositionList(String userId, String positionLearnId, String postId, String gradeId, FtbCultivatePosition position) {
        // 构建查询条件
        LambdaQueryWrapper<FtbCultivatePositionLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FtbCultivatePositionLog::getPostLearnId, positionLearnId)
                .eq(FtbCultivatePositionLog::getPostId, postId)
                .eq(Objects.equals(position.getIsConfiguredToGrade(), 1), FtbCultivatePositionLog::getGradeId, gradeId)
                .eq(FtbCultivatePositionLog::getUserId, userId)
                .eq(FtbCultivatePositionLog::getEnabledMark, 0); // 0-正常 1-删除

        List<FtbCultivatePositionLog> list = ftbCultivatePositionLogService.list(queryWrapper);

        // 如果没有找到记录，则创建一条新记录（状态：0-未完成）
        if (CollUtil.isEmpty(list)) {
            FtbCultivatePositionLog log = new FtbCultivatePositionLog();
            log.setPostLearnId(positionLearnId);
            log.setPostId(postId);
            if (Objects.equals(position.getIsConfiguredToGrade(), 1)) {
                log.setGradeId(gradeId);
            }
            log.setUserId(userId);
            log.setState(0); // 0-未完成 1-进行中 2-已完成
            log.setEnabledMark(0); // 0-正常
            ftbCultivatePositionLogService.save(log);
            return null;
        } else {
            // 如果第一条记录状态为已完成（2），则返回列表
            if (list.get(0).getState().equals(2)) {
                return list;
            }
        }

        return null;
    }


    @Transactional
    @Override
    public void dealPositionReCheckStudyItem(UserBoundVO userBoundVO, V2CultivatePostAndGradeVoExt itemVo, String tenantId) {
        String userId = userBoundVO.getId();
        String positionLearnId = itemVo.getId();
        String postId = itemVo.getPostId();
        String gradeId = itemVo.getGradeId();
        FtbCultivatePositionSetting positionSetting = itemVo.getSetting();
        List<FtbCultivatePositionCourse> courseList = ftbCultivatePositionCourseService.queryAllPositionCourseAndLearnIdAndGradeId(positionLearnId, gradeId);
        if (CollUtil.isEmpty(courseList)) {
            log.error("dealPositionReCheckStudyItem未查询到课程信息，positionLearnId={},gradeId={}, userId={}",
                    positionLearnId, gradeId, userId);
            return;
        }
        Map<String, jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning> courseLearningMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userId,
                courseList.stream().map(FtbCultivatePositionCourse::getCourseId).collect(Collectors.toList()));
        for (FtbCultivatePositionCourse ftbCultivatePositionCourse : courseList) {
            String courseId = ftbCultivatePositionCourse.getCourseId();
            //课程是否完成
            if (!checkItemCourseIsComplete(courseLearningMap, courseId)) {
                continue;
            }
            // 查询考试信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseExam> exams = ftbCultivatePositionCourseExamService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
            List<String> examIds = exams.stream().map(FtbCultivatePositionCourseExam::getExamId).distinct().collect(Collectors.toList());

            // 查询鉴定信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseIdentity> identities = ftbCultivatePositionCourseIdentityService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId), gradeId);
            List<String> identityIds = identities.stream().map(FtbCultivatePositionCourseIdentity::getIdentityId).distinct().collect(Collectors.toList());

            // 查询练习信息 - 使用新封装的方法
            List<FtbCultivatePositionCoursePractice> practices = ftbCultivatePositionCoursePracticeService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
            List<String> practiceIds = practices.stream().map(FtbCultivatePositionCoursePractice::getBusinessId).distinct().collect(Collectors.toList());
            Map<String, FtbCultivatePositionCoursePractice> practiceMap = new HashMap<>();
            if (CollUtil.isNotEmpty(practices)) {
                for (FtbCultivatePositionCoursePractice practice : practices) {
                    practiceMap.put(practice.getBusinessId(), practice);
                }
            }
            // 查询证书信息 - 使用新封装的方法
            List<FtbCultivatePositionCourseCertificate> certificates = ftbCultivatePositionCourseCertificateService.listByPostLearnIdAndCourseIds(positionLearnId, List.of(courseId));
            List<String> certificateIds = certificates.stream().map(FtbCultivatePositionCourseCertificate::getCertificateId).distinct().collect(Collectors.toList());

            // 批量查询用户的考试、鉴定、证书、技能完成情况
            Map<String, FtbCultivateExamUser> userExamStatusMap = v2CultivateBatchQueryService.batchQueryUserExamStatus(userId, examIds);
            Map<String, CultivateIdentifyApply> userIdentificationStatusMap = v2CultivateBatchQueryService.batchQueryUserIdentificationStatus(userId, identityIds, 2, ftbCultivatePositionCourse.getPostLearnId());
//        Map<String, FtbCertificateUserEntity> userCertificateStatusMap = v2CultivateBatchQueryService.batchQueryUserCertificateStatus(userId, certificateIds);
            Map<String, List<String>> userSkillStatusMap = v2CultivateBatchQueryService.batchQueryUserSkillStatus(userId, practiceIds);

            Integer qualified = 0; //试合格和练习满足才能完成鉴定【0-否 1-是】
            if (positionSetting != null) {
                qualified = positionSetting.getQualified();
            }

            // 检查考试、技能和鉴定状态
            PositionStatusResultVo positionStatusResult = evaluatePositionStatus(userId, positionLearnId, examIds, practiceIds, identityIds,
                    qualified, userExamStatusMap, userIdentificationStatusMap, practiceMap, userSkillStatusMap, courseId, ftbCultivatePositionCourse.getGradeId(), tenantId);

            handlePositionCourseCompletion(userId, positionLearnId, postId, gradeId, courseId, certificateIds, tenantId,
                    positionStatusResult);
        }

    }

    private V2CultivatePostAndGradeVoExt queryUserSelfPosition(UserBoundVO userPrimaryBoundOne) {
        List<FtbCultivatePosition> cultivatePositionList = ftbCultivatePositionService.list(
                Wrappers.<FtbCultivatePosition>lambdaQuery()
                        .eq(FtbCultivatePosition::getPostId, userPrimaryBoundOne.getPositionId())
                        .eq(FtbCultivatePosition::getIsGrounding, 1)
                        .eq(FtbCultivatePosition::getEnabledMark, 0));

        if (CollUtil.isEmpty(cultivatePositionList)) {
            return null;
        }


        FtbCultivatePosition cultivatePosition = cultivatePositionList.get(0);

        LambdaQueryWrapper<FtbCultivatePositionSetting> settingWrapper = Wrappers.lambdaQuery();
        settingWrapper.eq(FtbCultivatePositionSetting::getPostLearnId, cultivatePosition.getId());
        List<FtbCultivatePositionSetting> settingList = ftbCultivatePositionSettingService.list(settingWrapper);

        if (cultivatePosition.getIsConfiguredToGrade().equals(0))//未分配到职级
        {
            V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVo = new V2CultivatePostAndGradeVoExt();
            v2CultivatePostAndGradeVo.setPostId(cultivatePosition.getPostId());
            v2CultivatePostAndGradeVo.setId(cultivatePosition.getId());
            v2CultivatePostAndGradeVo.setGradeId("");
            if (CollUtil.isNotEmpty(settingList)) {
                v2CultivatePostAndGradeVo.setSetting(settingList.get(0));
            }
            return v2CultivatePostAndGradeVo;
        } else {

            if (StringUtils.isEmpty(userPrimaryBoundOne.getGradeId())) {
                return null;
            }
            for (FtbCultivatePositionSetting ftbCultivatePositionSetting : settingList) {
                if (ftbCultivatePositionSetting.getGradeId().equals(userPrimaryBoundOne.getGradeId())) {
                    V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVo = new V2CultivatePostAndGradeVoExt();
                    v2CultivatePostAndGradeVo.setPostId(cultivatePosition.getPostId());
                    v2CultivatePostAndGradeVo.setId(cultivatePosition.getId());
                    v2CultivatePostAndGradeVo.setGradeId(ftbCultivatePositionSetting.getGradeId());
                    v2CultivatePostAndGradeVo.setSetting(ftbCultivatePositionSetting);
                    return v2CultivatePostAndGradeVo;
                }
            }
            return null;
        }
    }

    private Map<String, V2CultivatePostAndGradeVoExt> convertV2CultivatePostAndGradeVoMap(List<V2CultivatePostAndGradeVoExt> v2CultivatePostAndGradeVos) {
        if (CollUtil.isEmpty(v2CultivatePostAndGradeVos)) {
            return new HashMap<>();
        }
        Map<String, V2CultivatePostAndGradeVoExt> ret = new HashMap<>();
        for (V2CultivatePostAndGradeVoExt v2CultivatePostAndGradeVo : v2CultivatePostAndGradeVos) {
            ret.put(v2CultivatePostAndGradeVo.getPostId() + "-" + v2CultivatePostAndGradeVo.getGradeId(), v2CultivatePostAndGradeVo);
        }
        return ret;
    }

    private List<V2CultivatePostAndGradeVoExt> queryAllPositionAndGrade() {
        LambdaQueryWrapper<FtbCultivatePosition> positionWrapper = Wrappers.lambdaQuery();
        positionWrapper.eq(FtbCultivatePosition::getIsGrounding, 1);
        positionWrapper.eq(FtbCultivatePosition::getEnabledMark, 0); // 仅查询有效的岗位
        List<FtbCultivatePosition> positionList = ftbCultivatePositionService.list(positionWrapper);

        if (CollUtil.isEmpty(positionList)) {
            return List.of();
        }

        // 提取ID列表并在一次遍历中完成
        List<String> learnIds = new ArrayList<>(positionList.size());
        for (FtbCultivatePosition ftbCultivatePosition : positionList) {
            learnIds.add(ftbCultivatePosition.getId());
        }

        // 获取所有岗位对应的职级配置
        LambdaQueryWrapper<FtbCultivatePositionSetting> settingWrapper = Wrappers.lambdaQuery();
        settingWrapper.in(FtbCultivatePositionSetting::getPostLearnId, learnIds);
        List<FtbCultivatePositionSetting> settingList = ftbCultivatePositionSettingService.list(settingWrapper);

        // 构建岗位学习ID到职级列表的映射
        Map<String, List<FtbCultivatePositionSetting>> positionSettingMap = settingList.stream()
                .collect(Collectors.groupingBy(
                        FtbCultivatePositionSetting::getPostLearnId,
                        Collectors.toList()
                ));
        List<V2CultivatePostAndGradeVoExt> ret = new ArrayList<>();
        for (FtbCultivatePosition ftbCultivatePosition : positionList) {
            List<FtbCultivatePositionSetting> positionSettings = positionSettingMap.get(ftbCultivatePosition.getId());
            if (CollUtil.isEmpty(positionSettings)) {
                V2CultivatePostAndGradeVoExt postAndGradeVo = new V2CultivatePostAndGradeVoExt();
                postAndGradeVo.setId(ftbCultivatePosition.getId());
                postAndGradeVo.setPostId(ftbCultivatePosition.getPostId());
                postAndGradeVo.setGradeId("");
                postAndGradeVo.setSetting(null);
                ret.add(postAndGradeVo);
            } else {
                for (FtbCultivatePositionSetting positionSetting : positionSettings) {
                    V2CultivatePostAndGradeVoExt postAndGradeVo = new V2CultivatePostAndGradeVoExt();
                    postAndGradeVo.setId(ftbCultivatePosition.getId());
                    postAndGradeVo.setPostId(ftbCultivatePosition.getPostId());
                    postAndGradeVo.setGradeId(positionSetting.getGradeId());
                    postAndGradeVo.setSetting(positionSetting);
                    ret.add(postAndGradeVo);
                }
            }
        }
        return ret;
    }


    /**
     * 按照level字段对List<FtbCultivatePromotionPostNew>进行分组并分别排序（升序）
     *
     * @param list 待处理的FtbCultivatePromotionPostNew列表
     * @return 按level分组后每组内按升序排列的Map
     */
    public Map<Integer, List<FtbCultivatePromotionPostNew>> groupAndSortByLevel(List<FtbCultivatePromotionPostNew> list) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }

        return list.stream()
                .collect(Collectors.groupingBy(
                        FtbCultivatePromotionPostNew::getLevel,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                subList -> {
                                    subList.sort(Comparator.comparingInt(FtbCultivatePromotionPostNew::getLevel));
                                    return subList;
                                }
                        )
                ));
    }


    /**
     * 根据学习地图id批量查询地图中配置的岗位并按照学习地图id分组
     *
     * @param promotionIds 学习地图id列表
     * @return 以学习地图id为key，岗位列表为value的Map
     */
    public Map<String, List<FtbCultivatePromotionPostNew>> batchQueryPositionsByPromotionIds(List<String> promotionIds) {
        if (CollUtil.isEmpty(promotionIds)) {
            return new HashMap<>();
        }

        // 构建查询条件，查询属于这些学习地图的所有岗位
        LambdaQueryWrapper<FtbCultivatePromotionPostNew> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(FtbCultivatePromotionPostNew::getPromotionId, promotionIds)
                .eq(FtbCultivatePromotionPostNew::getDeleteMark, 0);

        List<FtbCultivatePromotionPostNew> positionList = ftbCultivatePromotionPostNewService.list(queryWrapper);

        // 按照学习地图id进行分组
        return positionList.stream()
                .collect(Collectors.groupingBy(FtbCultivatePromotionPostNew::getPromotionId));
    }


    /**
     * 删除申请详情
     *
     * @param appId 鉴定id
     */
    private void deleteApplyDetails(String appId) {
        applyDetailsService.update(new LambdaUpdateWrapper<CultivateIdentifyApplyDetails>().set(CultivateIdentifyApplyDetails::getDeleteMark, 1).eq(CultivateIdentifyApplyDetails::getApplyId, appId).eq(CultivateIdentifyApplyDetails::getDeleteMark, 0));
    }

    /**
     * 触发考试
     *
     * @param userId   用户id
     * @param examId   考试id
     * @param source   来源
     * @param sourceId 来源id
     */
    public FtbCultivateExamUser triggerExam(String userId, String examId, Integer source, String sourceId, String tenantId) {
        log.error("triggerExam userId={},examId={},source={},sourceId={}", userId, examId, source, sourceId);
        CultivateExam ftbCultivateExam = v2CultivateExamMapper.selectById(examId);
        if (ftbCultivateExam == null) {
            log.error("triggerExam 考试不存在在 userId={},examId={},source={},sourceId={}", userId, examId, source, sourceId);
            return null;
        }

        //查看是否有记录
        LambdaQueryWrapper<FtbCultivateExamUser> wrapper = new LambdaQueryWrapper<FtbCultivateExamUser>().eq(FtbCultivateExamUser::getUserId, userId).eq(FtbCultivateExamUser::getExamId, examId).eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode()).orderByDesc(FtbCultivateExamUser::getCreatorTime);
        List<FtbCultivateExamUser> examUserList = ftbCultivateExamUserMapper.selectList(wrapper);
        if (CollUtil.isNotEmpty(examUserList)) {
            log.error("triggerExam 考试已经完成或存在 userId={},examId={},source={},sourceId={}", userId, examId, source, sourceId);
            return examUserList.get(0);
        }

//        LambdaQueryWrapper<FtbCultivateExamUser> wrapperNoComplete = new LambdaQueryWrapper<FtbCultivateExamUser>().eq(FtbCultivateExamUser::getUserId, userId).eq(FtbCultivateExamUser::getExamId, examId).in(FtbCultivateExamUser::getStatus, 0, 2).eq(FtbCultivateExamUser::getEnabledMark, CourseEnums.EnabledMarkType.VALID.getCode());
//        List<FtbCultivateExamUser> examUserListComplete = ftbCultivateExamUserMapper.selectList(wrapperNoComplete);
//        if (CollUtil.isNotEmpty(examUserListComplete)) {
//            log.error("triggerExam 考试已经存在 userId={},examId={},source={},sourceId={}", userId, examId, source, sourceId);
//            return;
//        }


        List<CultivateExamDrawRule> ruleList = examDrawRuleService.list(new LambdaQueryWrapper<CultivateExamDrawRule>().eq(CultivateExamDrawRule::getExamId, ftbCultivateExam.getId()));


        //2、没有就写入一条记录
        FtbCultivateExamUser user = FtbCultivateExamUser.builder()
                .examId(examId)
                .examType(ftbCultivateExam.getExamType())
                .userId(userId)
                .status(CourseEnums.ExamStatus.WAIT.getCode())
                .examSource(source)
                .enabledMark(CourseEnums.EnabledMarkType.VALID.getCode())
                .batch(UUID.randomUUID().toString().replaceAll("-", ""))
                .userExamCount(1).build();
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userPrimaryBoundOne != null && userPrimaryBoundOne.getOrganizeId() != null) {
            user.setUserOrgList(userPrimaryBoundOne.getOrganizeId());
        }
        if (CollUtil.isNotEmpty(ruleList)) {
            user.setPickQuestionRule(JSON.toJSONString(ruleList));
            int totalScore = 0;
            int questionNumber = 0;
            for (CultivateExamDrawRule cultivateExamDrawRule : ruleList) {
                totalScore += cultivateExamDrawRule.getScore() * cultivateExamDrawRule.getPickCount();
                questionNumber += cultivateExamDrawRule.getPickCount();
            }
            user.setTotalScore(totalScore);
            user.setQuestionNumber(questionNumber);
            user.setPassScore(QuestionAnalysisUtil.calPassScore(totalScore, ftbCultivateExam));
            user.setExcellentScore(QuestionAnalysisUtil.calExcellentScore(totalScore, ftbCultivateExam));
            user.setExamTime(ftbCultivateExam.getExamTime());
        }
        if (source.equals(2)) {
            user.setRelationPositionId(sourceId);
        } else if (source.equals(4)) {
            user.setRelationTaskId(sourceId);
        }
        ftbCultivateExamUserMapper.insert(user);
        log.error("triggerExam 生成考试记录 userId={},examId={},source={},sourceId={}", userId, examId, source, sourceId);
        return user;
    }

    /**
     * 触发鉴定
     *
     * @param userId     用户id
     * @param identifyId 鉴定id
     * @param source     鉴定来源(0手动发起，1课程学习鉴定，2岗位学习鉴定，3本人申请,4任务鉴定)
     * @param sourceId   鉴定来源id
     */
    public CultivateIdentifyApply triggerIdentification(String userId, String identifyId, Integer source, String sourceId, String tenantId) {
        log.info("触发鉴定  userId={},  identifyId={},  source={},  sourceId ={}", userId, identifyId, source, sourceId);
        CultivateIdentifyTable table = identifyTableService.getById(identifyId);
        if (table == null) {
            log.error("鉴定表不存在  userId={},  identifyId={},  source={},  sourceId ={}", userId, identifyId, source, sourceId);
            return null;
        }

        List<CultivateIdentifyItems> identifyItemsList = this.identifyItemsService.lambdaQuery().eq(CultivateIdentifyItems::getTableId, table.getId()).eq(CultivateIdentifyItems::getDeleteMark, ConstantUtil.NUM_FALSE).list();
        if (CollUtil.isEmpty(identifyItemsList)) {
            log.error("鉴定表项不存在  userId={},  identifyId={},  source={},  sourceId ={}", userId, identifyId, source, sourceId);
        }
        UserBoundVO userBoundVO = userApiV2Util.getUserPrimaryBoundOne(userId, tenantId);
        if (userBoundVO == null) {
            return null;
        }
        LambdaQueryWrapper<CultivateIdentifyApply> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CultivateIdentifyApply::getSourceId, sourceId);
        wrapper.eq(CultivateIdentifyApply::getSource, source);
        wrapper.eq(CultivateIdentifyApply::getOriginalTableId, table.getId());
        wrapper.eq(CultivateIdentifyApply::getBeIdentifyUserId, userId);
        wrapper.eq(CultivateIdentifyApply::getDeleteMark, ConstantUtil.NUM_FALSE);
        wrapper.orderByDesc(CultivateIdentifyApply::getCreatorTime);
        List<CultivateIdentifyApply> oldApplyLists = identifyApplyService.list(wrapper);

        if (CollUtil.isNotEmpty(oldApplyLists)) {
            CultivateIdentifyApply oldApply = oldApplyLists.get(0);
            if (oldApply.getStatus().equals(1) || oldApply.getStatus().equals(0)) {
                return oldApply;
            }
            oldApply.setDeleteMark(1);
            deleteApplyDetails(oldApply.getId());
            identifyApplyService.updateById(oldApply);
        }
        CultivateIdentifyApply apply = new CultivateIdentifyApply();
        apply.setId(UUID.randomUUID().toString());
        apply.setIdentifyUserId("");
        apply.setIdentifyOrgList("");
        apply.setSourceId(sourceId);
        apply.setSource(source);
        apply.setTableId(table.getId());
        apply.setOriginalTableId(table.getId());
        apply.setName(table.getName());
        apply.setBeIdentifyUserId(userId);
        apply.setStatus(ApplyStatusEnum.DJD.getCode());
        apply.setAppraisalResults(ConstantUtil.NUM_FALSE);
        apply.setUseTime(0);
        apply.setIsVisible(0);

        //设置被鉴定人信息
        apply.setIsChoose(ConstantUtil.NUM_FALSE);
        apply.setStudyFinishTime(new Date());
        apply.setIsReIdentify(ConstantUtil.NUM_FALSE);
        apply.setDeleteMark(0);
        // 岗位学习和课程实操鉴定，不进行直属主管判定，因为直属主管需要组织、岗位、职等进行确定

        //被鉴定人组织信息
        List<UserOrgInfoAll1Vo> beIdentifyUserInfoJsonList = CollUtil.newArrayList();
        UserOrgInfoAll1Vo all1Vo = new UserOrgInfoAll1Vo();
        all1Vo.setUserOrgCode(userBoundVO.getOrganizeEnCode());
        all1Vo.setUserOrgName(userBoundVO.getOrganizeName());
        all1Vo.setUserPostCode(userBoundVO.getPositionEnCode());
        all1Vo.setUserPostName(userBoundVO.getPositionName());
        all1Vo.setUserOfficialRankCode(userBoundVO.getGradeId());
        all1Vo.setUserOfficialRankName(userBoundVO.getGradeName());
        beIdentifyUserInfoJsonList.add(all1Vo);

        apply.setBeIdentifyOrgList(userBoundVO.getOrganizeId());
        apply.setBeOfficialRankInfoJson(JSON.toJSONString(beIdentifyUserInfoJsonList));

        //生成鉴定表、鉴定项备份数据
        CultivateIdentifyApplyTableBackups applyTableBackups = new CultivateIdentifyApplyTableBackups();
        BeanUtils.copyProperties(table, applyTableBackups);
        applyTableBackups.setId(RandomUtil.uuId());
        applyTableBackups.setTableId(table.getId());
        apply.setTableId(applyTableBackups.getId());

        List<CultivateIdentifyApplyDetailsBackups> applyDetailsBackupsList = CollUtil.newArrayList();
        if (CollUtil.isNotEmpty(identifyItemsList)) {
            applyDetailsBackupsList.addAll(identifyItemsList.stream().map(item -> {
                CultivateIdentifyApplyDetailsBackups applyDetailsBackups = new CultivateIdentifyApplyDetailsBackups();
                BeanUtils.copyProperties(item, applyDetailsBackups);
                applyDetailsBackups.setId(RandomUtil.uuId());
                applyDetailsBackups.setItemsId(item.getId());
                applyDetailsBackups.setTableId(applyTableBackups.getId());
                applyDetailsBackups.setDeleteMark(0);
                return applyDetailsBackups;
            }).collect(Collectors.toList()));
        }
        //生成鉴定项数据
        List<CultivateIdentifyApplyDetails> applyDetailsList = CollUtil.newArrayList();

        applyDetailsList.addAll(applyDetailsBackupsList.stream().map(item -> {
            CultivateIdentifyApplyDetails applyDetails = new CultivateIdentifyApplyDetails();
            applyDetails.setApplyId(apply.getId());
            applyDetails.setItemsId(item.getId());
            applyDetails.setDeleteMark(0);
            return applyDetails;
        }).collect(Collectors.toList()));
        //保存备份数据
        applyTableBackupsService.save(applyTableBackups);
        if (CollUtil.isNotEmpty(applyDetailsBackupsList)) {
            applyDetailsBackupsService.saveBatch(applyDetailsBackupsList);
        }

        if (CollUtil.isNotEmpty(applyDetailsList)) {
            this.applyDetailsService.saveBatch(applyDetailsList);
        }
        identifyApplyService.save(apply);
        return apply;
    }

    /**
     * 鉴定表项是否触发证书颁发
     *
     * @param userId          用户id
     * @param certificateId   证书id
     * @param positionLearnId 岗位学习id
     * @param postId          岗位id
     * @param gradeId         职级id
     * @param courseId        课程id
     * @return true-已经触发过了  false-未触发
     */
    public Boolean checkIsTriggerPositionCertificate(String userId, String certificateId, String positionLearnId, String postId, String gradeId, String courseId) {
        //查询是否颁发
        LambdaQueryWrapper<FtbCultivateCertificateResult> certificateResultLambdaQueryWrapper = Wrappers.lambdaQuery();
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getUserId, userId);
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getCertificateId, certificateId);
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getPositionLearnId, positionLearnId);
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getPostRankId, postId);
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getGradeId, gradeId);
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getCourseId, courseId);
        certificateResultLambdaQueryWrapper.eq(FtbCultivateCertificateResult::getType, 1);//来源，1：岗位学习证书，2：课程证书  3： 任务证书
        return ftbCultivateCertificateResultMapper.selectCount(certificateResultLambdaQueryWrapper) > 0;

    }

    /**
     * 记录触发的证书
     *
     * @param userId          用户id
     * @param certificateId   证书id
     * @param positionLearnId 岗位学习id
     * @param postId          岗位id
     * @param gradeId         职级id
     * @param courseId        课程id
     */
    private void recordTriggerPositionCertificate(String userId, String certificateId, String positionLearnId, String postId, String gradeId, String courseId) {
        FtbCultivateCertificateResult cultivateCertificateResult = new FtbCultivateCertificateResult();
        cultivateCertificateResult.setUserId(userId);
        cultivateCertificateResult.setCertificateId(certificateId);
        cultivateCertificateResult.setPositionLearnId(positionLearnId);
        cultivateCertificateResult.setPostRankId(postId);
        cultivateCertificateResult.setGradeId(gradeId);
        cultivateCertificateResult.setCourseId(courseId);
        cultivateCertificateResult.setType(1);//来源，1：岗位学习证书，2：课程证书  3： 任务证书
        ftbCultivateCertificateResultMapper.insert(cultivateCertificateResult);
    }

    /**
     * 触发证书
     *
     * @param userId        用户id
     * @param certificateId 证书id
     * @param tenantId      租户id
     */
    public void triggerCertificate(String userId, String certificateId, String tenantId) {
        v2CultivateCertificateService.triggerCertificate(userId, certificateId, tenantId);
    }


    /**
     * 检查课程是否完成
     *
     * @param courseList 课程列表
     * @param userId     用户ID
     * @return false-未完成 true-完成
     */
    private Boolean checkCourseIsComplete(List<String> courseList, String userId) {
        Map<String, jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning> map = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userId, courseList);
        if (CollUtil.isEmpty(map)) {
            return false;
        }
        for (String courseId : courseList) {
            jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning courceLearning = map.get(courseId);
            if (courceLearning == null || courceLearning.getState() != 1) {
                return false;
            }
        }
        //记录
        return true;
    }

    /**
     * 检查单个课程是否完成
     *
     * @param courseLearningMap 学习列表
     * @param courseId          课程id
     * @return false-未完成 true-完成
     */
    private Boolean checkItemCourseIsComplete(Map<String, jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning> courseLearningMap, String courseId) {
        jnpf.model.cultivate.po.position.FtbCultivatePositionCourceLearning courseLearning = courseLearningMap.get(courseId);
        if (courseLearning == null || courseLearning.getState() == null) {
            return false;
        }
        return courseLearning.getState() == 1;
    }

}