package jnpf.cultivate.v2.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jnpf.base.vo.PageListVO;
import jnpf.cultivate.mapper.*;
import jnpf.cultivate.service.FtbCultivatePositionCourseCertificateService;
import jnpf.cultivate.service.FtbCultivatePositionCoursePracticeService;
import jnpf.cultivate.service.FtbCultivatePositionCourseService;
import jnpf.cultivate.service.impl.FtbCultivatePositionCourceLearningService;
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.CultivateIdentifyApply;
import jnpf.entity.cultivate.CultivateIdentifyTable;
import jnpf.entity.cultivate.CultivatePositionCourseLogEntity;
import jnpf.enums.cultivate.v2.mq.CultivateTypeEnum;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.cultivate.dto.position.FtbJobLearningPaginDTO;
import jnpf.model.cultivate.po.FtbCultivatePositionCourseCertificate;
import jnpf.model.cultivate.po.certificate.FtbCertificateUserEntity;
import jnpf.model.cultivate.po.course.FtbCultivateCourse;
import jnpf.model.cultivate.po.exam.FtbCultivateExam;
import jnpf.model.cultivate.po.exam.FtbCultivateExamUser;
import jnpf.model.cultivate.po.position.*;
import jnpf.model.cultivate.po.promotion.FtbCultivatePromotionMemberNew;
import jnpf.model.cultivate.po.promotion.FtbCultivatePromotionNew;
import jnpf.model.cultivate.po.promotion.FtbCultivatePromotionPostNew;
import jnpf.model.cultivate.v2.course.vo.app.*;
import jnpf.model.cultivate.v2.course.web.req.V2NextUserCultivateCourseListReq;
import jnpf.model.cultivate.v2.enums.PositionBusinessSourceEnum;
import jnpf.model.cultivate.v2.position.req.*;
import jnpf.model.cultivate.v2.position.vo.*;
import jnpf.model.cultivate.v2.promotion.vo.PromotionAndPostVo;
import jnpf.model.cultivate.v2.promotion.vo.V2CultivatePostAndGradeVo;
import jnpf.model.cultivate.v2.promotion.vo.V2CultivatePromotionErrorVo;
import jnpf.model.cultivate.vo.promotion.FtbCultivatePromotionVO;
import jnpf.permission.vo.v2.grades.GradeVO;
import jnpf.permission.vo.v2.position.PositionVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
@Slf4j
public class V2CultivatePositionServiceImpl implements V2CultivatePositionService {
    @Autowired
    private UserApiV2Util userApiV2Util;
    @Autowired
    private FtbCultivatePositionCourseService ftbCultivatePositionCourseService;
    @Autowired
    private FtbCultivatePositionCourseExamService ftbCultivatePositionCourseExamService;
    @Autowired
    private FtbCultivatePositionCourseIdentityService ftbCultivatePositionCourseIdentityService;
    @Autowired
    private FtbCultivatePositionCoursePracticeService ftbCultivatePositionCoursePracticeService;
    @Autowired
    private FtbCultivatePositionCourseCertificateService ftbCultivatePositionCourseCertificateService;
    @Autowired
    private FtbCultivatePositionSettingService ftbCultivatePositionSettingService;

    @Autowired
    private V2CultivateBatchQueryService v2CultivateBatchQueryService;

    @Autowired
    private FtbCultivatePositionCourceLearningService ftbCultivatePositionCourceLearningService;

    @Autowired
    private FtbCultivatePositionLogService ftbCultivatePositionLogService;

    @Autowired
    private CultivatePositionCourseLogService cultivatePositionCourseLogService;

    @Autowired
    private FtbCultivatePromotionNewMapper ftbCultivatePromotionNewMapper;

    @Autowired
    private FtbCultivatePromotionMemberNewMapper ftbCultivatePromotionMemberNewMapper;

    @Autowired
    private FtbCultivateCourseMapper ftbCultivateCourseMapper;

    @Autowired
    private FtbCultivatePositionMapper ftbCultivatePositionMapper;

    @Autowired
    private FtbCultivatePositionExamMapper ftbCultivatePositionExamMapper;

    @Autowired
    private V2CultivatePostStudyService v2CultivatePostStudyService;

    @Resource
    private ThreadPoolExecutor cultivateThreadPool;


    /**
     * 分页查询岗位学习列表
     *
     * @param req 分页查询请求参数，包含当前页码和页面大小等信息
     * @return 返回岗位学习列表的分页数据，每页包含课程、考试、鉴定、学习地图的数量统计
     */
    public Page<WebPositionLearningListVo> webPageList(FtbJobLearningPaginDTO req) {
        Page<WebPositionLearningListVo> page = Page.of(req.getCurrentPage(), req.getPageSize());

        Page<WebPositionLearningListVo> result = ftbCultivatePositionMapper.webPageList(page, req);
        List<WebPositionLearningListVo> records = result.getRecords();
        if (CollUtil.isNotEmpty(records)) {
            // 获取所有岗位学习ID列表
            List<String> positionLearnIds = records.stream()
                    .map(WebPositionLearningListVo::getId)
                    .collect(Collectors.toList());

            // 根据岗位学习ids 统计出课程数量 map<String,Long>
            Map<String, Long> courseCountMap = ftbCultivatePositionCourseService.countByPositionLearnIds(positionLearnIds);

            // 根据岗位学习ids 统计出考试数量 map<String,Long>
            Map<String, Long> examCountMap = ftbCultivatePositionCourseExamService.countByPositionLearnIds(positionLearnIds);

            // 根据岗位学习ids 统计出鉴定数量 map<String,Long>
            Map<String, Long> identityCountMap = ftbCultivatePositionCourseIdentityService.countByPositionLearnIds(positionLearnIds);

            //查询学习地图
            List<String> positionIds = records.stream()
                    .map(WebPositionLearningListVo::getPostId)
                    .collect(Collectors.toList());
            List<PromotionAndPostVo> listCount = ftbCultivatePromotionNewMapper.countByPositionIds(positionIds);
            Map<String, Long> promotionCountMap = buildPromotionNumMap(listCount);

            //批量查询岗位名称
            Map<String, PositionVO> positionVOMap = userApiV2Util.listPositionDetailInfoByIdsReturnMap(positionIds, null);
            // 回填每个岗位学习的课程 考试 鉴定 实践/练习的数量
            for (WebPositionLearningListVo record : records) {
                record.setCourseNum(courseCountMap.getOrDefault(record.getId(), 0L));
                record.setExamNum(Math.toIntExact(examCountMap.getOrDefault(record.getId(), 0L)));
                record.setIdentificationNum(identityCountMap.getOrDefault(record.getId(), 0L));
                record.setMapNum(promotionCountMap.getOrDefault(record.getPostId(), 0L));
                PositionVO positionVO = positionVOMap.get(record.getPostId());
                if (positionVO != null) {
                    record.setPostName(positionVO.getFullName());
                    record.setPostCustomId(positionVO.getEnCode());
                }
            }
        }

        return result;
    }

    /**
     * 构建促销数量映射表
     * 根据帖子ID对促销数据进行分组统计，返回每个帖子ID对应的促销数量
     *
     * @param listCount 促销与帖子视图对象列表，包含帖子ID等信息
     * @return Map<String, Long> 以帖子ID为键、对应促销数量为值的映射表
     */
    private Map<String, Long> buildPromotionNumMap(List<PromotionAndPostVo> listCount) {
        if (CollUtil.isEmpty(listCount)) {
            return new HashMap<>();
        }
        return listCount.stream()
                .collect(Collectors.groupingBy(
                        PromotionAndPostVo::getPostId,
                        Collectors.counting()
                ));
    }


    /**
     * 添加岗位学习
     *
     * @param ftbCultivatePosition 岗位学习实体
     * @return 操作结果
     */
    @Override
    @Transactional
    public String add(FtbCultivatePositionSaveReq ftbCultivatePosition) {
        ftbCultivatePosition.preCheckParams();
        v2CultivateBatchQueryService.positionCheckAvailable(ftbCultivatePosition);

        LambdaQueryWrapper<FtbCultivatePosition> positionWrapper = Wrappers.lambdaQuery();
        positionWrapper.eq(FtbCultivatePosition::getPostId, ftbCultivatePosition.getPostId())
                .eq(FtbCultivatePosition::getEnabledMark, 0);

        FtbCultivatePosition existingPosition = ftbCultivatePositionMapper.selectOne(positionWrapper);

        if (existingPosition != null) {
            throw new RuntimeException("该岗位已经配置了岗位学习,请不要重复操作");
        }

        FtbCultivatePosition newPosition = new FtbCultivatePosition();
        newPosition.setPostId(ftbCultivatePosition.getPostId());
        newPosition.setIsConfiguredToGrade(ftbCultivatePosition.getIsConfiguredToGrade());
        newPosition.setIsGrounding(PositionConstants.IS_GROUNDING_ONLINE);
        newPosition.setLastModifyTime(new Date());
        newPosition.setLastModifyUserId(UserProvider.getLoginUserId());
        ftbCultivatePositionMapper.insert(newPosition);

        realDealPosition(ftbCultivatePosition, newPosition.getId());

        return newPosition.getId();
    }

    /**
     * 处理岗位学习数据
     *
     * @param ftbCultivatePosition 岗位学习实体
     * @param cultivatePositionId  岗位学习ID
     */
    private void realDealPosition(FtbCultivatePositionSaveReq ftbCultivatePosition, String cultivatePositionId) {

        if (CollUtil.isEmpty(ftbCultivatePosition.getCourseList())) {
            return;
        }
        // 准备批量插入的数据集合
        List<FtbCultivatePositionCourse> positionCourses = new ArrayList<>();
        List<FtbCultivatePositionCourseExam> positionCourseExams = new ArrayList<>();
        List<FtbCultivatePositionCourseIdentity> positionCourseIdentitys = new ArrayList<>();
        List<FtbCultivatePositionCoursePractice> positionCoursePractices = new ArrayList<>();
        List<FtbCultivatePositionCourseCertificate> positionCourseCertificates = new ArrayList<>();

        for (FtbCultivatePositionCourseReq courseReq : ftbCultivatePosition.getCourseList()) {
            // 添加岗位学习课程表记录
            FtbCultivatePositionCourse positionCourse = new FtbCultivatePositionCourse();
            positionCourse.setCourseId(courseReq.getCourseId());
            positionCourse.setPostLearnId(cultivatePositionId);
            positionCourse.setPostRankId(ftbCultivatePosition.getPostId());
            positionCourse.setCompulsory(courseReq.getCompulsory());

            positionCourse.setGradeId(courseReq.getGradeId());
            positionCourse.setSortCode(courseReq.getSortCode());

            positionCourse.setEnabledMark(0);
            positionCourses.add(positionCourse);

            // 添加岗位学习课程考试表记录
            if (courseReq.getExam() != null) {
                positionCourseExams.add(getFtbCultivatePositionCourseExam(ftbCultivatePosition, cultivatePositionId, courseReq));
            }

            // 添加岗位学习课程鉴定表记录
            if (courseReq.getIdentity() != null) {
                positionCourseIdentitys.add(getFtbCultivatePositionCourseIdentity(ftbCultivatePosition, cultivatePositionId, courseReq));
            }

            // 添加岗位学习课程练习表记录
            if (CollUtil.isNotEmpty(courseReq.getPracticeList())) {
                for (FtbCultivatePositionCoursePracticeReq practiceReq : courseReq.getPracticeList()) {
                    positionCoursePractices.add(buildFtbCultivatePositionCoursePractice(ftbCultivatePosition, cultivatePositionId, courseReq, practiceReq));
                }
            }

            // 添加岗位学习课程证书表记录
            if (courseReq.getCertificate() != null) {
                positionCourseCertificates.add(getFtbCultivatePositionCourseCertificate(ftbCultivatePosition, cultivatePositionId, courseReq));
            }
        }
        //添加配置数据
        List<FtbCultivatePositionSettingReq> setting = ftbCultivatePosition.getSetting();
        if (CollUtil.isNotEmpty(setting)) {
            ftbCultivatePositionSettingService.saveBatch(getFtbCultivatePositionSettings(ftbCultivatePosition, cultivatePositionId, setting));
        }
        // 批量保存数据
        if (CollUtil.isNotEmpty(positionCourses)) {
            ftbCultivatePositionCourseService.saveBatch(positionCourses);
        }
        if (CollUtil.isNotEmpty(positionCourseExams)) {
            ftbCultivatePositionCourseExamService.saveBatch(positionCourseExams);
        }
        if (CollUtil.isNotEmpty(positionCourseIdentitys)) {
            ftbCultivatePositionCourseIdentityService.saveBatch(positionCourseIdentitys);
        }
        if (CollUtil.isNotEmpty(positionCoursePractices)) {
            ftbCultivatePositionCoursePracticeService.saveBatch(positionCoursePractices);
        }
        if (CollUtil.isNotEmpty(positionCourseCertificates)) {
            ftbCultivatePositionCourseCertificateService.saveBatch(positionCourseCertificates);
        }

    }

    @NotNull
    private static FtbCultivatePositionCoursePractice buildFtbCultivatePositionCoursePractice(FtbCultivatePositionSaveReq ftbCultivatePosition, String cultivatePositionId, FtbCultivatePositionCourseReq courseReq, FtbCultivatePositionCoursePracticeReq practiceReq) {
        FtbCultivatePositionCoursePractice positionCoursePractice = new FtbCultivatePositionCoursePractice();
        positionCoursePractice.setCourseId(courseReq.getCourseId());
        positionCoursePractice.setPostLearnId(cultivatePositionId);
        positionCoursePractice.setBusinessId(practiceReq.getBusinessId());
        positionCoursePractice.setPostRankId(ftbCultivatePosition.getPostId());
        positionCoursePractice.setNum(practiceReq.getNum());
        positionCoursePractice.setGradeId(courseReq.getGradeId());
        positionCoursePractice.setEnabledMark(0);
        return positionCoursePractice;
    }

    @NotNull
    private static List<FtbCultivatePositionSetting> getFtbCultivatePositionSettings(FtbCultivatePositionSaveReq ftbCultivatePosition, String cultivatePositionId, List<FtbCultivatePositionSettingReq> setting) {
        List<FtbCultivatePositionSetting> ftbCultivatePositionSettings = new ArrayList<>();
        for (FtbCultivatePositionSettingReq ftbCultivatePositionSettingReq : setting) {
            FtbCultivatePositionSetting ftbCultivatePositionSetting = new FtbCultivatePositionSetting();
            ftbCultivatePositionSetting.setPostLearnId(cultivatePositionId);
            ftbCultivatePositionSetting.setPostRankId(ftbCultivatePosition.getPostId());
            ftbCultivatePositionSetting.setQualified(ftbCultivatePositionSettingReq.getQualified());
            ftbCultivatePositionSetting.setGradeId(ftbCultivatePositionSettingReq.getGradeId());
            ftbCultivatePositionSettings.add(ftbCultivatePositionSetting);
        }
        return ftbCultivatePositionSettings;
    }

    @NotNull
    private static FtbCultivatePositionCourseCertificate getFtbCultivatePositionCourseCertificate(FtbCultivatePositionSaveReq ftbCultivatePosition, String cultivatePositionId, FtbCultivatePositionCourseReq courseReq) {
        FtbCultivatePositionCourseCertificate positionCourseCertificate = new FtbCultivatePositionCourseCertificate();
        positionCourseCertificate.setCourseId(courseReq.getCourseId());
        positionCourseCertificate.setPostLearnId(cultivatePositionId);
        positionCourseCertificate.setPostRankId(ftbCultivatePosition.getPostId());
        positionCourseCertificate.setCertificateId(courseReq.getCertificate().getCertificateId());
        positionCourseCertificate.setGradeId(courseReq.getGradeId());
        positionCourseCertificate.setEnabledMark(0);
        return positionCourseCertificate;
    }

    @NotNull
    private static FtbCultivatePositionCourseIdentity getFtbCultivatePositionCourseIdentity(FtbCultivatePositionSaveReq ftbCultivatePosition, String cultivatePositionId, FtbCultivatePositionCourseReq courseReq) {
        FtbCultivatePositionCourseIdentity positionCourseIdentity = new FtbCultivatePositionCourseIdentity();
        positionCourseIdentity.setCourseId(courseReq.getCourseId());
        positionCourseIdentity.setPostLearnId(cultivatePositionId);
        positionCourseIdentity.setPostRankId(ftbCultivatePosition.getPostId());
        positionCourseIdentity.setIdentityId(courseReq.getIdentity().getIdentityId());
        positionCourseIdentity.setGradeId(courseReq.getGradeId());
        positionCourseIdentity.setEnabledMark(0);
        return positionCourseIdentity;
    }

    @NotNull
    private static FtbCultivatePositionCourseExam getFtbCultivatePositionCourseExam(FtbCultivatePositionSaveReq ftbCultivatePosition, String cultivatePositionId, FtbCultivatePositionCourseReq courseReq) {
        FtbCultivatePositionCourseExam positionCourseExam = new FtbCultivatePositionCourseExam();
        positionCourseExam.setCourseId(courseReq.getCourseId());
        positionCourseExam.setPostLearnId(cultivatePositionId);
        positionCourseExam.setPostRankId(ftbCultivatePosition.getPostId());
        positionCourseExam.setExamId(courseReq.getExam().getExamId());
        positionCourseExam.setGradeId(courseReq.getGradeId());
        positionCourseExam.setEnabledMark(0);
        return positionCourseExam;
    }

    /**
     * 修改岗位学习
     *
     * @param ftbCultivatePosition 岗位学习实体
     * @return 操作结果
     */
    @Override
    @Transactional
    public String update(FtbCultivatePositionSaveReq ftbCultivatePosition) {
        //入参检查
        if (ftbCultivatePosition == null || StringUtils.isEmpty(ftbCultivatePosition.getId())) {
            throw new RuntimeException("岗位学习信息不能为空");
        }

        //入参检查
        ftbCultivatePosition.preCheckParams();
        v2CultivateBatchQueryService.positionCheckAvailable(ftbCultivatePosition);
        //查询原有岗位学习主表信息
        FtbCultivatePosition existingPosition = ftbCultivatePositionMapper.selectById(ftbCultivatePosition.getId());
        if (existingPosition == null) {
            throw new RuntimeException("未找到对应的岗位学习信息");
        }
        if (existingPosition.getEnabledMark().equals(1)) {
            throw new RuntimeException("岗位学习信息不存在");
        }


        // 检查是否已存在相同的岗位ID，如果存在则更新
        LambdaQueryWrapper<FtbCultivatePosition> positionWrapper = Wrappers.lambdaQuery();
        positionWrapper.eq(FtbCultivatePosition::getPostId, ftbCultivatePosition.getPostId())
                .eq(FtbCultivatePosition::getEnabledMark, 0);
        FtbCultivatePosition existingPositionByPostId = ftbCultivatePositionMapper.selectOne(positionWrapper);

        if (existingPositionByPostId != null && !existingPositionByPostId.getId().equals(existingPosition.getId())) {
            throw new RuntimeException("该岗位已经配置了岗位学习,请不要重复操作");
        }

        //修改岗位学习主表
        existingPosition.setPostId(ftbCultivatePosition.getPostId());
        existingPosition.setIsConfiguredToGrade(ftbCultivatePosition.getIsConfiguredToGrade());
        existingPosition.setIsGrounding(1);
        existingPosition.setLastModifyTime(new Date());
        existingPosition.setLastModifyUserId(UserProvider.getLoginUserId());
        ftbCultivatePositionMapper.updateById(existingPosition);
        deleteCultivateRelation(existingPosition.getId());
        realDealPosition(ftbCultivatePosition, existingPosition.getId());
        return existingPosition.getId();
    }

    /**
     * 删除岗位学习
     *
     * @param id 岗位学习ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteCultivateRelation(String id) {
        log.info("开始删除岗位学习关联数据, postLearnId={}", id);
        try {
            LambdaUpdateWrapper<FtbCultivatePositionCourse> courseWrapper = Wrappers.lambdaUpdate();
            courseWrapper.eq(FtbCultivatePositionCourse::getPostLearnId, id);
            courseWrapper.set(FtbCultivatePositionCourse::getEnabledMark, PositionConstants.ENABLED_MARK_DELETED);
            ftbCultivatePositionCourseService.update(courseWrapper);

            LambdaUpdateWrapper<FtbCultivatePositionCourseExam> examWrapper = Wrappers.lambdaUpdate();
            examWrapper.eq(FtbCultivatePositionCourseExam::getPostLearnId, id);
            examWrapper.set(FtbCultivatePositionCourseExam::getEnabledMark, PositionConstants.ENABLED_MARK_DELETED);
            ftbCultivatePositionCourseExamService.update(examWrapper);

            LambdaUpdateWrapper<FtbCultivatePositionCourseIdentity> identityWrapper = Wrappers.lambdaUpdate();
            identityWrapper.eq(FtbCultivatePositionCourseIdentity::getPostLearnId, id);
            identityWrapper.set(FtbCultivatePositionCourseIdentity::getEnabledMark, PositionConstants.ENABLED_MARK_DELETED);
            ftbCultivatePositionCourseIdentityService.update(identityWrapper);

            LambdaUpdateWrapper<FtbCultivatePositionCoursePractice> practiceWrapper = Wrappers.lambdaUpdate();
            practiceWrapper.eq(FtbCultivatePositionCoursePractice::getPostLearnId, id);
            practiceWrapper.set(FtbCultivatePositionCoursePractice::getEnabledMark, PositionConstants.ENABLED_MARK_DELETED);
            ftbCultivatePositionCoursePracticeService.update(practiceWrapper);

            LambdaUpdateWrapper<FtbCultivatePositionCourseCertificate> certificateWrapper = Wrappers.lambdaUpdate();
            certificateWrapper.eq(FtbCultivatePositionCourseCertificate::getPostLearnId, id);
            certificateWrapper.set(FtbCultivatePositionCourseCertificate::getEnabledMark, PositionConstants.ENABLED_MARK_DELETED);
            ftbCultivatePositionCourseCertificateService.update(certificateWrapper);

            LambdaQueryWrapper<FtbCultivatePositionSetting> settingWrapper = Wrappers.lambdaQuery();
            settingWrapper.eq(FtbCultivatePositionSetting::getPostLearnId, id);
            ftbCultivatePositionSettingService.remove(settingWrapper);

            LambdaUpdateWrapper<FtbCultivatePositionLog> logWrapper = Wrappers.lambdaUpdate();
            logWrapper.eq(FtbCultivatePositionLog::getPostLearnId, id);
            logWrapper.set(FtbCultivatePositionLog::getEnabledMark, PositionConstants.ENABLED_MARK_DELETED);
            ftbCultivatePositionLogService.update(logWrapper);

            //删除岗位学习ftb_cultivate_position_course_log中数据 F_EnabledMark=1
            LambdaUpdateWrapper<CultivatePositionCourseLogEntity> courseLogWrapper = Wrappers.lambdaUpdate();
            courseLogWrapper.eq(CultivatePositionCourseLogEntity::getPostLearnId, id);
            cultivatePositionCourseLogService.remove(courseLogWrapper);


            log.info("岗位学习关联数据删除完成, postLearnId={}", id);
        } catch (Exception e) {
            log.error("删除岗位学习关联数据失败, postLearnId={}", id, e);
            throw new RuntimeException("删除岗位学习关联数据失败", e);
        }
    }

    /**
     * 删除岗位学习
     *
     * @param id 岗位学习id
     * @return 操作结果
     */
    @Override
    @Transactional
    public String delete(String id) {
        validateId(id, "岗位学习");

        FtbCultivatePosition existingPosition = ftbCultivatePositionMapper.selectById(id);
        if (existingPosition == null) {
            throw new RuntimeException("未找到对应的岗位学习信息");
        }
        if (existingPosition.getEnabledMark().equals(1)) {
            throw new RuntimeException("岗位学习信息不存在");
        }
        existingPosition.setEnabledMark(1);
        ftbCultivatePositionMapper.updateById(existingPosition);

        deleteCultivateRelation(id);
        //学习地图异常
        List<FtbCultivatePromotionPostNew> promotionPostNewList = ftbCultivatePromotionMemberNewMapper.queryRelationMap(existingPosition.getPostId());
        if (CollUtil.isNotEmpty(promotionPostNewList)) {
            // 按学习地图ID进行分组
            Map<String, List<FtbCultivatePromotionPostNew>> promotionIdMap =
                    promotionPostNewList.stream().collect(Collectors.groupingBy(FtbCultivatePromotionPostNew::getPromotionId));

            for (Map.Entry<String, List<FtbCultivatePromotionPostNew>> entry : promotionIdMap.entrySet()) {
                String promotionId = entry.getKey();
                List<FtbCultivatePromotionPostNew> promotionPosts = entry.getValue();

                // 转换异常岗位信息
                List<V2CultivatePostAndGradeVo> jsonList = new ArrayList<>();
                if (CollUtil.isNotEmpty(promotionPosts)) {
                    for (FtbCultivatePromotionPostNew promotionPost : promotionPosts) {
                        V2CultivatePostAndGradeVo json = new V2CultivatePostAndGradeVo();
                        json.setPostId(promotionPost.getPostId());
                        json.setPostName(promotionPost.getPostName());
                        json.setGradeId(promotionPost.getGradeId());
                        json.setGradeName(promotionPost.getGradeName());
                        jsonList.add(json);
                    }
                }

                // 创建异常信息VO
                V2CultivatePromotionErrorVo vo = new V2CultivatePromotionErrorVo();
                vo.setPositionLearnDel(jsonList);
                // 更新学习地图状态
                ftbCultivatePromotionNewMapper.update(new FtbCultivatePromotionNew(),
                        new UpdateWrapper<FtbCultivatePromotionNew>().lambda()
                                .eq(FtbCultivatePromotionNew::getId, promotionId)
                                .set(FtbCultivatePromotionNew::getIsError, 1)
                                .set(FtbCultivatePromotionNew::getErrorMsg, JSONUtil.toJsonStr(vo))
                );
            }
        }
        return "success";
    }

    /**
     * 获取岗位学习信息
     *
     * @param id 岗位学习ID
     * @return 岗位学习信息
     */
    @Override
    public WebCultivatePositionVo get(String id) {
        validateId(id, "岗位学习");

        FtbCultivatePosition position = ftbCultivatePositionMapper.selectById(id);
        if (position == null) {
            throw new RuntimeException("未找到对应的岗位学习信息");
        }

        WebCultivatePositionVo vo = new WebCultivatePositionVo();
        vo.convert(position);
        enrichWithPostInfo(vo, position.getPostId());
        enrichWithCourseListData(vo, id, position);

        return vo;
    }

    private void validateId(String id, String entityName) {
        if (StringUtils.isEmpty(id)) {
            throw new RuntimeException(entityName + "ID不能为空");
        }
    }

    private void enrichWithPostInfo(WebCultivatePositionVo vo, String postId) {
        PositionVO positionVO = userApiV2Util.infoPosition(postId, null);
        if (positionVO != null) {
            vo.setPostName(positionVO.getFullName());
            vo.setPostEncode(positionVO.getEnCode());
        }
        vo.setGradeVOList(userApiV2Util.listGrades(postId, null));
    }

    private void enrichWithCourseListData(WebCultivatePositionVo vo, String postLearnId, FtbCultivatePosition position) {
        List<FtbCultivatePositionCourseWithNameVo> courses = ftbCultivatePositionCourseService.listByPostLearnIdWithName(postLearnId, "");

        if (CollUtil.isEmpty(courses)) {
            vo.setFtbCultivatePositionCourseList(new ArrayList<>());
            return;
        }

        List<String> courseIds = extractCourseIds(courses);

        CourseRelatedData relatedData = batchQueryRelatedData(postLearnId, courseIds);

        List<FtbCultivatePositionCourseVo> courseVos = buildCourseVoList(courses, relatedData);
        List<String> positionLearnIds = courseVos.stream()
                .map(FtbCultivatePositionCourseVo::getPostLearnId)
                .filter(StrUtil::isNotBlank)
                .distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(positionLearnIds)) {
            vo.setFtbCultivatePositionCourseList(courseVos);
            return;
        }
        List<FtbCultivatePositionSetting> settings = ftbCultivatePositionSettingService
                .list(Wrappers.<FtbCultivatePositionSetting>lambdaQuery()
                        .in(FtbCultivatePositionSetting::getPostLearnId, positionLearnIds));
        List<FtbCultivatePositionSettingVo> settingVoList = new ArrayList<>();
        for (FtbCultivatePositionSetting setting : settings) {
            FtbCultivatePositionSettingVo settingVo = new FtbCultivatePositionSettingVo();
            settingVo.setId(setting.getId());
            settingVo.setGradeId(setting.getGradeId());
            settingVo.setQualified(setting.getQualified());
            settingVoList.add(settingVo);
        }
        vo.setFtbCultivatePositionCourseList(courseVos);
        vo.setFtbCultivatePositionGradeList(settingVoList);
    }

    private List<String> extractCourseIds(List<FtbCultivatePositionCourseWithNameVo> courses) {
        return courses.stream()
                .map(FtbCultivatePositionCourseWithNameVo::getCourseId)
                .distinct()
                .collect(Collectors.toList());
    }

    private CourseRelatedData batchQueryRelatedData(String postLearnId, List<String> courseIds) {
        List<FtbCultivatePositionCourseExamWithNameVo> exams = ftbCultivatePositionCourseExamService.listByPostLearnIdWithName(postLearnId);
        List<FtbCultivatePositionCourseIdentityWithNameVo> identities = ftbCultivatePositionCourseIdentityService.listByPostLearnIdWithName(postLearnId);
        List<FtbCultivatePositionCoursePracticeWithNameVo> practices = ftbCultivatePositionCoursePracticeService.listByPostLearnIdWithName(postLearnId);
        List<FtbCultivatePositionCourseCertificateWithNameVo> certificates = ftbCultivatePositionCourseCertificateService.listByPostLearnIdWithName(postLearnId);

        return new CourseRelatedData(exams, identities, practices, certificates);
    }

    private List<FtbCultivatePositionCourseVo> buildCourseVoList(List<FtbCultivatePositionCourseWithNameVo> courses, CourseRelatedData relatedData) {
        List<FtbCultivatePositionCourseVo> courseVos = new ArrayList<>();
        for (FtbCultivatePositionCourseWithNameVo course : courses) {
            FtbCultivatePositionCourseVo courseVo = convertToCourseVo(course);
            courseVo.setExam(findExamForCourse(course, relatedData.exams));
            courseVo.setIdentity(findIdentityForCourse(course, relatedData.identities));
            courseVo.setPracticeList(findPracticesForCourse(course, relatedData.practices));
            courseVo.setCertificate(findCertificateForCourse(course, relatedData.certificates));
            courseVos.add(courseVo);
        }
        return courseVos;
    }

    private FtbCultivatePositionCourseVo convertToCourseVo(FtbCultivatePositionCourseWithNameVo course) {
        FtbCultivatePositionCourseVo courseVo = new FtbCultivatePositionCourseVo();
        courseVo.setId(course.getId());
        courseVo.setCourseId(course.getCourseId());
        courseVo.setCourseName(course.getCourseName());
        courseVo.setCourseIdShow(course.getShowCourseId());
        courseVo.setPostRankId(course.getPostRankId());
        courseVo.setGradeId(course.getGradeId());
        courseVo.setPostLearnId(course.getPostLearnId());
        courseVo.setCompulsory(course.getCompulsory());
        courseVo.setSortCode(course.getSortCode() != null ? course.getSortCode().longValue() : PositionConstants.DEFAULT_SORT_CODE);
        return courseVo;
    }

    private FtbCultivatePositionCourseExamVo findExamForCourse(FtbCultivatePositionCourseWithNameVo course, List<FtbCultivatePositionCourseExamWithNameVo> exams) {
        return exams.stream()
                .filter(e -> e.getCourseId().equals(course.getCourseId()) && isGradeMatch(e.getGradeId(), course.getGradeId()))
                .findFirst()
                .map(this::convertToExamVo)
                .orElse(null);
    }

    private FtbCultivatePositionCourseIdentityVo findIdentityForCourse(FtbCultivatePositionCourseWithNameVo course, List<FtbCultivatePositionCourseIdentityWithNameVo> identities) {
        return identities.stream()
                .filter(i -> i.getCourseId().equals(course.getCourseId()) && isGradeMatch(i.getGradeId(), course.getGradeId()))
                .findFirst()
                .map(this::convertToIdentityVo)
                .orElse(null);
    }

    private List<FtbCultivatePositionCoursePracticeVo> findPracticesForCourse(FtbCultivatePositionCourseWithNameVo course, List<FtbCultivatePositionCoursePracticeWithNameVo> practices) {
        return practices.stream()
                .filter(p -> p.getCourseId().equals(course.getCourseId()) && isGradeMatch(p.getGradeId(), course.getGradeId()))
                .map(this::convertToPracticeVo)
                .collect(Collectors.toList());
    }

    private FtbCultivatePositionCourseCertificateVo findCertificateForCourse(FtbCultivatePositionCourseWithNameVo course, List<FtbCultivatePositionCourseCertificateWithNameVo> certificates) {
        return certificates.stream()
                .filter(c -> c.getCourseId().equals(course.getCourseId()) && isGradeMatch(c.getGradeId(), course.getGradeId()))
                .findFirst()
                .map(this::convertToCertificateVo)
                .orElse(null);
    }

    private boolean isGradeMatch(String relatedGradeId, String courseGradeId) {
        return relatedGradeId == null || relatedGradeId.equals(courseGradeId);
    }

    private FtbCultivatePositionCourseExamVo convertToExamVo(FtbCultivatePositionCourseExamWithNameVo exam) {
        FtbCultivatePositionCourseExamVo examVo = new FtbCultivatePositionCourseExamVo();
        examVo.setId(exam.getId());
        examVo.setExamId(exam.getExamId());
        examVo.setExamName(exam.getExamName());
        examVo.setPostRankId(exam.getPostRankId());
        examVo.setGradeId(exam.getGradeId());
        return examVo;
    }

    private FtbCultivatePositionCourseIdentityVo convertToIdentityVo(FtbCultivatePositionCourseIdentityWithNameVo identity) {
        FtbCultivatePositionCourseIdentityVo identityVo = new FtbCultivatePositionCourseIdentityVo();
        identityVo.setId(identity.getId());
        identityVo.setIdentityId(identity.getIdentityId());
        identityVo.setIdentityName(identity.getIdentityName());
        identityVo.setPostRankId(identity.getPostRankId());
        identityVo.setGradeId(identity.getGradeId());
        return identityVo;
    }

    private FtbCultivatePositionCoursePracticeVo convertToPracticeVo(FtbCultivatePositionCoursePracticeWithNameVo practice) {
        FtbCultivatePositionCoursePracticeVo practiceVo = new FtbCultivatePositionCoursePracticeVo();
        practiceVo.setId(practice.getId());
        practiceVo.setNum(practice.getNum());
        practiceVo.setBusinessId(practice.getBusinessId());
        practiceVo.setBusinessName(practice.getBusinessName());
        practiceVo.setPostRankId(practice.getPostRankId());
        practiceVo.setGradeId(practice.getGradeId());
        return practiceVo;
    }

    private FtbCultivatePositionCourseCertificateVo convertToCertificateVo(FtbCultivatePositionCourseCertificateWithNameVo certificate) {
        FtbCultivatePositionCourseCertificateVo certificateVo = new FtbCultivatePositionCourseCertificateVo();
        certificateVo.setId(certificate.getId());
        certificateVo.setCertificateId(certificate.getCertificateId());
        certificateVo.setCertificateName(certificate.getCertificateName());
        certificateVo.setPostRankId(certificate.getPostRankId());
        certificateVo.setPostLearnId(certificate.getPostLearnId());
        certificateVo.setCourseId(certificate.getCourseId());
        certificateVo.setGradeId(certificate.getGradeId());
        return certificateVo;
    }

    private static class CourseRelatedData {
        final List<FtbCultivatePositionCourseExamWithNameVo> exams;
        final List<FtbCultivatePositionCourseIdentityWithNameVo> identities;
        final List<FtbCultivatePositionCoursePracticeWithNameVo> practices;
        final List<FtbCultivatePositionCourseCertificateWithNameVo> certificates;

        CourseRelatedData(List<FtbCultivatePositionCourseExamWithNameVo> exams,
                          List<FtbCultivatePositionCourseIdentityWithNameVo> identities,
                          List<FtbCultivatePositionCoursePracticeWithNameVo> practices,
                          List<FtbCultivatePositionCourseCertificateWithNameVo> certificates) {
            this.exams = exams;
            this.identities = identities;
            this.practices = practices;
            this.certificates = certificates;
        }
    }

    /**
     * 根据id查询岗位学习配置总览
     *
     * @param id 岗位学习id
     * @return 岗位学习配置总览
     */
    @Override
    public WebCultivatePositionView webView(String id) {
        validateId(id, "岗位学习");

        FtbCultivatePosition position = ftbCultivatePositionMapper.selectById(id);
        if (position == null) {
            throw new RuntimeException("未找到对应的岗位学习信息");
        }

        WebCultivatePositionView view = new WebCultivatePositionView();
        view.setId(position.getId());
        view.setPostId(position.getPostId());

        setPostInfo(view, position.getPostId());
        setCourseList(view, id);
        setExamInfo(view, id);
        setIdentityInfo(view, id);
        setPromotionInfo(view, position.getPostId());

        return view;
    }

    /**
     * 设置岗位信息
     */
    private void setPostInfo(WebCultivatePositionView view, String postId) {
        PositionVO positionVO = userApiV2Util.infoPosition(postId, null);
        if (positionVO != null) {
            view.setPostName(positionVO.getFullName());
            view.setPostCode(positionVO.getEnCode());
        }
    }

    /**
     * 设置课程列表
     */
    private void setCourseList(WebCultivatePositionView view, String id) {
        List<FtbCultivatePositionCourseWithNameVo> courses = ftbCultivatePositionCourseService.listByPostLearnId(id, "");
        if (CollUtil.isEmpty(courses)) {
            view.setCourseList(new ArrayList<>());
            return;
        }

        List<String> courseIds = courses.stream()
                .map(FtbCultivatePositionCourseWithNameVo::getCourseId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询课程基础信息
        Map<String, FtbCultivateCourse> courseBasicInfoMap = v2CultivateBatchQueryService.batchQueryCoursesByIds(courseIds, null);

        // 构建课程列表VO
        List<CourseSimpleVo> courseSimpleVos = courses.stream()
                .map(course -> buildCourseSimpleVo(course, courseBasicInfoMap))
                .collect(Collectors.toList());
        view.setCourseList(courseSimpleVos);
    }

    /**
     * 构建课程简单VO
     */
    private CourseSimpleVo buildCourseSimpleVo(FtbCultivatePositionCourseWithNameVo course, Map<String, FtbCultivateCourse> courseBasicInfoMap) {
        CourseSimpleVo courseSimpleVo = new CourseSimpleVo();
        courseSimpleVo.setId(course.getCourseId());
        FtbCultivateCourse courseBasicInfo = courseBasicInfoMap.get(course.getCourseId());
        if (courseBasicInfo != null) {
            courseSimpleVo.setName(courseBasicInfo.getName());
            courseSimpleVo.setIsGroundIng(courseBasicInfo.getIsGroundIng());
            courseSimpleVo.setCourseId(courseBasicInfo.getCourseId());
        }
        return courseSimpleVo;
    }

    /**
     * 设置考试信息
     */
    private void setExamInfo(WebCultivatePositionView view, String id) {
        List<FtbCultivatePositionCourseExam> exams = ftbCultivatePositionCourseExamService.listByPostLearnId(id);
        if (CollUtil.isEmpty(exams)) {
            view.setExamVoList(new ArrayList<>());
            return;
        }

        // 获取考试ID列表并批量查询考试基础信息
        List<String> examIds = exams.stream()
                .map(FtbCultivatePositionCourseExam::getExamId)
                .distinct()
                .collect(Collectors.toList());


        Map<String, FtbCultivateExam> examBasicInfoMap = v2CultivateBatchQueryService.batchQueryExamsByIds(examIds, null);

        // 构建考试VO列表
        List<FtbCultivatePositionCourseExamVo> examVoList = exams.stream()
                .map(exam -> {
                    FtbCultivatePositionCourseExamVo examVo = new FtbCultivatePositionCourseExamVo();
                    examVo.convert(exam);
                    FtbCultivateExam examBasicInfo = examBasicInfoMap.get(exam.getExamId());
                    if (examBasicInfo != null) {
                        examVo.setExamName(examBasicInfo.getExamName());
                    }
                    return examVo;
                })
                .collect(Collectors.toList());

        view.setExamVoList(examVoList);
    }

    /**
     * 设置鉴定信息
     */
    private void setIdentityInfo(WebCultivatePositionView view, String id) {
        List<FtbCultivatePositionCourseIdentity> identities = ftbCultivatePositionCourseIdentityService.listByPostLearnId(id);
        if (CollUtil.isEmpty(identities)) {
            view.setIdentityVoList(new ArrayList<>());
            return;
        }

        // 获取鉴定ID列表并批量查询鉴定基础信息
        List<String> identityIds = identities.stream()
                .map(FtbCultivatePositionCourseIdentity::getIdentityId)
                .distinct()
                .collect(Collectors.toList());

        Map<String, CultivateIdentifyTable> identityBasicInfoMap = v2CultivateBatchQueryService.batchQueryIdentificationsByIds(identityIds, null);

        // 构建鉴定VO列表
        List<FtbCultivatePositionCourseIdentityVo> identityVoList = identities.stream()
                .map(identity -> {
                    FtbCultivatePositionCourseIdentityVo identityVo = new FtbCultivatePositionCourseIdentityVo();
                    identityVo.convert(identity);
                    CultivateIdentifyTable identityBasicInfo = identityBasicInfoMap.get(identity.getIdentityId());
                    if (identityBasicInfo != null) {
                        identityVo.setIdentityName(identityBasicInfo.getName());
                    }
                    return identityVo;
                })
                .collect(Collectors.toList());

        view.setIdentityVoList(identityVoList);
    }

    /**
     * 设置学习地图信息
     */
    private void setPromotionInfo(WebCultivatePositionView view, String postId) {
        List<String> positionIds = List.of(postId);
        List<PromotionAndPostVo> promotionList = ftbCultivatePromotionNewMapper.countByPositionIds(positionIds);

        if (CollUtil.isEmpty(promotionList)) {
            return;
        }
        List<FtbCultivatePromotionVO> voList = new ArrayList<>();
        for (PromotionAndPostVo promotionAndPostVo : promotionList) {
            voList.add(promotionAndPostVo.convert());
        }
        view.setPromotionVOList(voList);
    }

    /**
     * app岗位学习-本岗位学习课程列表
     *
     * @param req 岗位学习课程列表请求参数
     * @return 岗位学习课程列表
     */
    @Override
    public PositionLearningCourseVo positionCourseLists(V2CultivatePositionCourseForAppReq req) {
        // 1. 获取当前登录用户信息
        UserBoundVO userBoundVO = getUserBoundVO(req);
        // 2. 查询用户岗位ID
        String postId = userBoundVO.getPositionId();
        //用户的职级id
        String gradeId = userBoundVO.getGradeId();
        // 3. 查询岗位学习是否存在
        FtbCultivatePosition cultivatePosition = getFtbCultivatePosition(postId);
        if (cultivatePosition == null) {
            throw new RuntimeException("该岗位尚未配置岗位学习");
        }

        V2InnerPositionDto v2InnerPositionDto = new V2InnerPositionDto();
        v2InnerPositionDto.setKeyWord(req.getKeyWord());
        v2InnerPositionDto.setUserId(userBoundVO.getId());
        PositionLearningCourseVo positionLearningCourseVo = null;
        if (cultivatePosition.getIsConfiguredToGrade().equals(0))//未分配到职级
        {
            //根据岗位id查询课程列表
            positionLearningCourseVo = realQueryCourseListForPositionId(cultivatePosition, v2InnerPositionDto);
        } else {
            if (StringUtils.isNotEmpty(gradeId)) {
                //根据岗位id和职级id查询课程列表
                positionLearningCourseVo = realQueryCourseListForPositionIdAndGradeId(cultivatePosition, v2InnerPositionDto, gradeId);
            }
        }
        // 如果岗位配置到职级但用户没有职级，则返回空结果
        if (positionLearningCourseVo == null) {
            return PositionLearningCourseVo.empty();
        }
        List<AppCourseSimpleVo> courseLists = positionLearningCourseVo.getCourseLists();
        if (CollUtil.isNotEmpty(courseLists)) {
            Map<String, Long> studyNumMap = v2CultivateBatchQueryService.batchQueryCourseLearningCount(courseLists.stream().map(AppCourseSimpleVo::getCourseId).collect(Collectors.toList()));
            for (AppCourseSimpleVo vo : courseLists) {
                vo.setLearnTotalNumber(studyNumMap.getOrDefault(vo.getCourseId(), 0L));
            }
        }
        return positionLearningCourseVo;
    }

    @NotNull
    private UserBoundVO getUserBoundVO(V2CultivatePositionCourseForAppReq req) {
        UserBoundVO userBoundVO = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (userBoundVO == null) {
            throw new RuntimeException("用户信息不存在");
        }
        // 2. 查询用户岗位ID
        String postId = userBoundVO.getPositionId();
        if (StringUtils.isEmpty(postId)) {
            throw new RuntimeException("用户未分配岗位");
        }
        return userBoundVO;
    }

    /**
     * 通用方法：查询课程列表核心逻辑
     */
    private PositionLearningCourseVo queryCourseListCore(FtbCultivatePosition cultivatePosition,
                                                         V2InnerPositionDto req,
                                                         List<FtbCultivatePositionCourseWithNameVo> positionCourses) {
        if (CollUtil.isEmpty(positionCourses)) {
            return PositionLearningCourseVo.empty();
        }

        // 获取课程ID列表，用于批量查询课程基础信息
        List<String> courseIds = positionCourses.stream()
                .map(FtbCultivatePositionCourseWithNameVo::getCourseId)
                .distinct()
                .collect(Collectors.toList());


        // 批量查询课程基础信息
        List<FtbCultivateCourse> courseList = ftbCultivateCourseMapper.selectList(Wrappers.<FtbCultivateCourse>lambdaQuery()
                .in(FtbCultivateCourse::getId, courseIds)
                .like(StringUtils.isNotEmpty(req.getKeyWord()), FtbCultivateCourse::getName, req.getKeyWord())
                .eq(FtbCultivateCourse::getIsGroundIng, 1)
                .eq(FtbCultivateCourse::getEnableMark, 0));
        if (CollUtil.isEmpty(courseList)) {
            return PositionLearningCourseVo.empty();
        }
        Map<String, Long> studyNumMap = v2CultivateBatchQueryService.batchQueryCourseLearningCount(courseIds);
        PositionLearningCourseVo result = new PositionLearningCourseVo();
        // 批量查询用户的学习记录
        List<FtbCultivatePositionCourceLearning> learningRecords = ftbCultivatePositionCourceLearningService.list(
                Wrappers.<FtbCultivatePositionCourceLearning>lambdaQuery()
                        .select(FtbCultivatePositionCourceLearning::getCourceId, FtbCultivatePositionCourceLearning::getState)
                        .eq(FtbCultivatePositionCourceLearning::getUserId, req.getUserId())
                        .in(FtbCultivatePositionCourceLearning::getCourceId, courseIds)
                        .eq(FtbCultivatePositionCourceLearning::getEnabledMark, 0)
        );

        // 构建学习记录映射
        Integer completedCount = 0;
        Map<String, Integer> learningStateMap = new HashMap<>();
        if (CollUtil.isNotEmpty(learningRecords)) {
            for (FtbCultivatePositionCourceLearning learningRecord : learningRecords) {
                completedCount += learningRecord.getState() == 1 ? 1 : 0;
                learningStateMap.put(learningRecord.getCourceId(), learningRecord.getState());
            }
        }
        // 7. 构建返回结果
        result.setAlreadyLearnedCourse(completedCount);
        result.setTotalCourse(courseList.size());

        List<AppCourseSimpleVo> appCourseSimpleVoList = new ArrayList<>();
        for (FtbCultivatePositionCourseWithNameVo positionCourse : positionCourses) {

            AppCourseSimpleVo courseVo = new AppCourseSimpleVo();
            courseVo.setBusinessSourceId(cultivatePosition.getId());
            courseVo.setBusinessSource(PositionBusinessSourceEnum.POST_LEARNING);
            courseVo.setCourseId(positionCourse.getCourseId());
            courseVo.setCourseName(positionCourse.getCourseName());
            courseVo.setCoverUrl(positionCourse.getCoverUrl());
            courseVo.setTypeId(positionCourse.getTypeId());
            courseVo.setPostId(cultivatePosition.getPostId()); // 使用参数传递的岗位ID

            // 设置学习状态
            Integer state = learningStateMap.get(positionCourse.getCourseId());
            if (state == null) {
                courseVo.setLearnState(0); // 未学习
            } else {
                courseVo.setLearnState(state); // 0未学习，1已学习，2学习中
            }

            // 设置学习总人数（暂时设为0，实际可从统计数据中获取）
            courseVo.setLearnTotalNumber(studyNumMap.get(positionCourse.getId()));
            appCourseSimpleVoList.add(courseVo);
        }

        result.setCourseLists(appCourseSimpleVoList);
        return result;
    }


    private PositionLearningCourseVo realQueryCourseListForPositionIdAndGradeId(FtbCultivatePosition cultivatePosition, V2InnerPositionDto req, String gradeId) {
        // 4. 根据岗位学习ID查询岗位学习课程列表
        List<FtbCultivatePositionCourseWithNameVo> positionCourses = ftbCultivatePositionCourseService.listByPostLearnIdAndGradeId(cultivatePosition.getId(), gradeId, "");
        return queryCourseListCore(cultivatePosition, req, positionCourses);
    }

    private PositionLearningCourseVo realQueryCourseListForPositionId(FtbCultivatePosition cultivatePosition, V2InnerPositionDto req) {
        // 根据岗位学习ID查询岗位学习课程列表
        List<FtbCultivatePositionCourseWithNameVo> positionCourses = ftbCultivatePositionCourseService.listByPostLearnId(cultivatePosition.getId(), "");
        return queryCourseListCore(cultivatePosition, req, positionCourses);
    }

    /**
     * app岗位学习-他岗位课程列表
     *
     * @param req 岗位学习课程列表请求参数
     * @return 岗位学习课程列表
     */
    @Override
    public List<CultivatePositionSimpleVo> otherPositionList(V2OtherCultivatePositionCourseForAppReq req) {
        // 1. 获取当前登录用户信息
        UserBoundVO userBoundVO = getUserBoundVO(req);

        // 2. 查询用户岗位ID
        String postId = userBoundVO.getPositionId();
        //用户的职级id
        String gradeId = userBoundVO.getGradeId();
        List<CultivatePositionSimpleVo> cultivatePosition = ftbCultivatePositionCourseService.queryAllPositionLearn(req.getKeyWord());
        if (CollUtil.isEmpty(cultivatePosition)) {
            return new ArrayList<>();
        }
        cultivatePosition = filterOtherPositionList(cultivatePosition, postId, gradeId);
        if (CollUtil.isEmpty(cultivatePosition)) {
            return new ArrayList<>();
        }
        //获取岗位ids 和 gradeIds
        List<String> postIds = new ArrayList<>();
        List<String> gradeIds = new ArrayList<>();
        for (CultivatePositionSimpleVo vo : cultivatePosition) {
            postIds.add(vo.getPostId());
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                gradeIds.add(vo.getGradeId());
            }
        }
        //批量查询岗位名称
        Map<String, PositionVO> stringPositionVOMap = userApiV2Util.listPositionDetailInfoByIdsReturnMap(postIds, null);
        Map<String, GradeVO> stringGradeVOMap = userApiV2Util.listGradeByIdsReturnMap(gradeIds, null);
        for (CultivatePositionSimpleVo vo : cultivatePosition) {
            PositionVO positionVO = stringPositionVOMap.get(vo.getPostId());
            if (positionVO != null) {
                vo.setPostName(positionVO.getFullName());
            }
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                GradeVO gradeVO = stringGradeVOMap.get(vo.getGradeId());
                if (gradeVO != null) {
                    vo.setGradeName(gradeVO.getFullName());
                }
            }
        }
        return cultivatePosition;
    }

    /**
     * 过滤其他岗位列表
     *
     * @param lists   岗位列表
     * @param postId  当前用户岗位ID
     * @param gradeId 当前用户职级ID
     * @param <T>     继承自 CultivatePositionSimpleVo 的类型
     * @return 过滤后的岗位列表
     */
    private <T extends CultivatePositionSimpleVo> List<T> filterOtherPositionList(List<T> lists, String postId, String gradeId) {
        List<T> returnList = new ArrayList<>();
        for (T vo : lists) {
            if (StringUtils.isEmpty(vo.getGradeId())) {
                if (!vo.getPostId().equals(postId)) {
                    returnList.add(vo);
                }
            } else {
                if (!vo.getPostId().equals(postId) || !vo.getGradeId().equals(gradeId)) {
                    returnList.add(vo);
                }
            }
        }
        return returnList;
    }


    /**
     * app岗位学习-他岗位课程（总课程/已经完成课程）
     *
     * @param req 岗位学习课程列表请求参数
     * @return 岗位学习课程列表
     */
    @Override
    public OtherPositionCourseCountVo otherPositionCourseCount(V2OtherCultivatePositionCourseForAppReq req) {

        UserBoundVO userBoundVO = getUserBoundVO(req);

        // 2. 查询用户岗位ID
        String postId = userBoundVO.getPositionId();
        //用户的职级id
        String gradeId = userBoundVO.getGradeId();
        OtherPositionCourseCountVo returnVo = new OtherPositionCourseCountVo();
        returnVo.init();
        List<AppCourseSimpleVo> list = ftbCultivatePositionCourseService.queryAllPositionLearnCourseLists(req);
        if (CollUtil.isEmpty(list)) {
            return returnVo;
        }
        list = filterOtherPositionList(list, postId, gradeId);
        Set<String> courseIds = new HashSet<>();
        for (AppCourseSimpleVo vo : list) {
            courseIds.add(vo.getCourseId());
        }
        returnVo.setTotalCourse(courseIds.size());

        Map<String, FtbCultivatePositionCourceLearning> stringFtbCultivatePositionCourceLearningMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userBoundVO.getId(), new ArrayList<>(courseIds));
        Long alreadyLearnedCourse = 0L;
        for (String courseId : courseIds) {
            FtbCultivatePositionCourceLearning ftbCultivatePositionCourceLearning = stringFtbCultivatePositionCourceLearningMap.get(courseId);
            if (ftbCultivatePositionCourceLearning != null && ftbCultivatePositionCourceLearning.getState() == 1) {
                alreadyLearnedCourse++;
            }
        }
        returnVo.setAlreadyLearnedCourse(alreadyLearnedCourse);
        return returnVo;
    }

    @Override
    public AppCultivatePositionDetailVo positionStudyDetail(V2CultivatePositionDetailForApp req) {
        // 初始化返回对象并验证请求参数
        AppCultivatePositionDetailVo returnVo = initializeAndValidateRequest(req);

        // 查询岗位学习配置信息
        FtbCultivatePosition existingPosition = queryPositionConfiguration(req);
        populatePositionInfo(returnVo, existingPosition);
        populatePositionState(returnVo, existingPosition, req);
        // 查询岗位学习设置
        populatePositionSettings(returnVo, existingPosition, req);

        // 查询岗位和职级信息
        populatePostAndGradeInfo(returnVo, req);
        existingPosition.setQualified(returnVo.getQualified());

        // 查询课程及关联的学习记录、考试、鉴定、练习、证书等信息
        List<AppCultivatePositionCourseVo> courseVoList = buildCourseListWithRelatedData(existingPosition, req);
        returnVo.setFtbCultivatePositionCourseList(courseVoList);
        for (AppCultivatePositionCourseVo appCultivatePositionCourseVo : courseVoList) {
            if (CollUtil.isNotEmpty(appCultivatePositionCourseVo.getExam())) {
                returnVo.getExam().addAll(appCultivatePositionCourseVo.getExam());
            }
            if (CollUtil.isNotEmpty(appCultivatePositionCourseVo.getIdentity())) {
                returnVo.getIdentity().addAll(appCultivatePositionCourseVo.getIdentity());
            }
            if (CollUtil.isNotEmpty(appCultivatePositionCourseVo.getPracticeList())) {
                returnVo.getPracticeList().addAll(appCultivatePositionCourseVo.getPracticeList());
            }
            if (CollUtil.isNotEmpty(appCultivatePositionCourseVo.getCertificate())) {
                returnVo.getCertificate().addAll(appCultivatePositionCourseVo.getCertificate());
            }
        }
        String tenantId = UserProvider.getUser().getTenantId();
        CompletableFuture.runAsync(() -> {
            userApiV2Util.checkOutTenant(tenantId);
            try {
                Integer hasExam = CollUtil.isEmpty(returnVo.getExam()) ? 1 : 2;
                Integer hasIdentify = CollUtil.isEmpty(returnVo.getIdentity()) ? 1 : 2;
                initPositionCourseLogs(existingPosition.getId(), existingPosition.getPostId(), req.getGradeId(), req.getUserId(), returnVo.getFtbCultivatePositionCourseList(), hasExam, hasIdentify);
            } catch (Exception e) {
                log.error("考试定时任务执行异常: {}", e.getMessage());
            }
        }, cultivateThreadPool);

        return returnVo;
    }

    private void populatePositionState(AppCultivatePositionDetailVo returnVo, FtbCultivatePosition existingPosition, V2CultivatePositionDetailForApp req) {
        LambdaQueryWrapper<FtbCultivatePositionLog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(FtbCultivatePositionLog::getUserId, req.getUserId())
                .eq(FtbCultivatePositionLog::getPostLearnId, existingPosition.getId())
                .eq(existingPosition.getIsConfiguredToGrade().equals(1), FtbCultivatePositionLog::getGradeId, req.getGradeId())
                .eq(FtbCultivatePositionLog::getEnabledMark, 0);
        List<FtbCultivatePositionLog> list = ftbCultivatePositionLogService.list(queryWrapper);
        if (CollUtil.isEmpty(list)) {
            returnVo.setPositionState(0);
            return;
        }
        returnVo.setPositionState(list.get(0).getState());
    }

    private void initPositionCourseLogs(String positionLearnId, String postId, String gradeId, String userId, List<AppCultivatePositionCourseVo> courseVoList, Integer hasExam, Integer hasIdentify) {
        if (CollUtil.isEmpty(courseVoList)) {
            return;
        }
        LambdaQueryWrapper<CultivatePositionCourseLogEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(CultivatePositionCourseLogEntity::getPostLearnId, positionLearnId)
                .eq(StringUtils.isNotEmpty(gradeId), CultivatePositionCourseLogEntity::getGradeId, gradeId)
                .eq(CultivatePositionCourseLogEntity::getUserId, userId)
                .eq(CultivatePositionCourseLogEntity::getEnabledMark, 0);
        List<CultivatePositionCourseLogEntity> logList = cultivatePositionCourseLogService.list(queryWrapper);
        if (CollUtil.isEmpty(logList)) {
            List<CultivatePositionCourseLogEntity> addList = new ArrayList<>();
            for (AppCultivatePositionCourseVo appCultivatePositionCourseVo : courseVoList) {
                CultivatePositionCourseLogEntity log = new CultivatePositionCourseLogEntity();
                log.setPostLearnId(positionLearnId);
                log.setPostId(postId);
                log.setGradeId(gradeId);
                log.setCourseId(appCultivatePositionCourseVo.getCourseId());
                log.setUserId(userId);
                log.setState(1);
                log.setHasExam(hasExam);
                log.setHasIdentity(hasIdentify);
                addList.add(log);
            }
            cultivatePositionCourseLogService.saveBatch(addList);
        }
    }

    /**
     * 初始化请求参数并进行验证
     */
    private AppCultivatePositionDetailVo initializeAndValidateRequest(V2CultivatePositionDetailForApp req) {
        AppCultivatePositionDetailVo returnVo = new AppCultivatePositionDetailVo();
        returnVo.setExam(new ArrayList<>());
        returnVo.setIdentity(new ArrayList<>());
        returnVo.setPracticeList(new ArrayList<>());
        returnVo.setCertificate(new ArrayList<>());
        String userId = UserProvider.getUser().getUserId();
        if (StringUtils.isEmpty(req.getUserId())) {
            req.setUserId(userId);
        }
        UserBoundVO userBoundVO = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (StringUtils.isEmpty(req.getPostId())) {
            req.setPostId(userBoundVO.getPositionId());
            req.setGradeId(userBoundVO.getGradeId());
        }
        return returnVo;
    }

    /**
     * 查询岗位学习配置信息
     */
    private FtbCultivatePosition queryPositionConfiguration(V2CultivatePositionDetailForApp req) {
        LambdaQueryWrapper<FtbCultivatePosition> positionWrapper = Wrappers.lambdaQuery();
        positionWrapper.eq(FtbCultivatePosition::getPostId, req.getPostId());
        positionWrapper.eq(FtbCultivatePosition::getIsGrounding, 1);
        positionWrapper.eq(FtbCultivatePosition::getEnabledMark, 0);

        FtbCultivatePosition existingPosition = ftbCultivatePositionMapper.selectOne(positionWrapper);

        if (existingPosition == null) {
            throw new RuntimeException("该岗位未配置岗位学习");
        }
        return existingPosition;
    }

    /**
     * 填充岗位基本信息到返回对象
     */
    private void populatePositionInfo(AppCultivatePositionDetailVo returnVo, FtbCultivatePosition existingPosition) {
        returnVo.setId(existingPosition.getId());
        returnVo.setPostId(existingPosition.getPostId());
        returnVo.setIsConfiguredToGrade(existingPosition.getIsConfiguredToGrade());
    }

    /**
     * 填充岗位学习设置信息
     */
    private void populatePositionSettings(AppCultivatePositionDetailVo returnVo, FtbCultivatePosition existingPosition, V2CultivatePositionDetailForApp req) {
        LambdaQueryWrapper<FtbCultivatePositionSetting> positionSettingWrapper = Wrappers.lambdaQuery();
        positionSettingWrapper.eq(FtbCultivatePositionSetting::getPostLearnId, existingPosition.getId());
        if (existingPosition.getIsConfiguredToGrade().equals(1)) {
            if (StringUtils.isEmpty(req.getGradeId())) {
                throw new RuntimeException("请传入用户的职级");
            }
            positionSettingWrapper.eq(FtbCultivatePositionSetting::getGradeId, req.getGradeId());
        }
        List<FtbCultivatePositionSetting> ftbCultivatePositionSettings = ftbCultivatePositionSettingService.list(positionSettingWrapper);
        if (CollUtil.isNotEmpty(ftbCultivatePositionSettings)) {
            returnVo.setQualified(ftbCultivatePositionSettings.get(0).getQualified());
        } else {
            returnVo.setQualified(0);
        }
    }

    /**
     * 填充岗位和职级信息
     */
    private void populatePostAndGradeInfo(AppCultivatePositionDetailVo returnVo, V2CultivatePositionDetailForApp req) {
        PositionVO positionVO = userApiV2Util.infoPosition(req.getPostId(), null);
        if (positionVO != null) {
            returnVo.setPostName(positionVO.getFullName());
            returnVo.setPostEncode(positionVO.getEnCode());
        }
        if (StringUtils.isNotEmpty(req.getGradeId())) {
            GradeVO gradeVO = userApiV2Util.infoGrade(req.getGradeId(), null);
            if (gradeVO != null) {
                returnVo.setGradeName(gradeVO.getName());
                returnVo.setGradeId(gradeVO.getId());
            }
        }
    }

    /**
     * 构建课程列表及其相关数据（考试、鉴定、练习、证书等）
     */
    private List<AppCultivatePositionCourseVo> buildCourseListWithRelatedData(FtbCultivatePosition existingPosition, V2CultivatePositionDetailForApp req) {
        // 1. 查询岗位学习课程列表
        List<FtbCultivatePositionCourseWithNameVo> positionCourses = queryPositionCourses(existingPosition, req);

        if (CollUtil.isEmpty(positionCourses)) {
            return new ArrayList<>();
        }

        // 获取课程ID列表，用于批量查询
        List<String> courseIds = positionCourses.stream()
                .map(FtbCultivatePositionCourseWithNameVo::getCourseId)
                .distinct()
                .collect(Collectors.toList());


        // 批量查询用户的学习记录
        Map<String, FtbCultivatePositionCourceLearning> learningMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(req.getUserId(), courseIds);
        Map<String, List<V2ChapterVo>> learningChapterMap = v2CultivateBatchQueryService.batchQueryUserCourseChapterLearnStatus(req.getUserId(), courseIds);

        // 查询课程关联的考试、鉴定、练习、证书信息
        RelatedDataBundle relatedData = queryRelatedDataBundle(existingPosition.getId(), courseIds, req.getUserId());

        // 构建课程列表VO
        return positionCourses.stream()
                .map(positionCourse -> buildCourseVo(existingPosition, positionCourse, learningMap, learningChapterMap, relatedData, req))
                .collect(Collectors.toList());
    }

    /**
     * 查询岗位学习课程列表
     */
    private List<FtbCultivatePositionCourseWithNameVo> queryPositionCourses(FtbCultivatePosition existingPosition, V2CultivatePositionDetailForApp req) {
        return ftbCultivatePositionCourseService.listPositionCourseList(existingPosition, req);
    }

    /**
     * 查询课程关联的所有相关数据
     */
    private RelatedDataBundle queryRelatedDataBundle(String postLearnId, List<String> courseIds, String userId) {
        // 查询课程关联的考试、鉴定、练习、证书信息 - 使用JOIN一次性获取基础信息
        List<FtbCultivatePositionCourseExamWithNameVo> positionCourseExams = ftbCultivatePositionCourseExamService.listByPostLearnIdAndCourseIdsWithName(postLearnId, courseIds);
        List<FtbCultivatePositionCourseIdentityWithNameVo> positionCourseIdentities = ftbCultivatePositionCourseIdentityService.listByPostLearnIdAndCourseIdsWithName(postLearnId, courseIds);
        List<FtbCultivatePositionCoursePracticeWithNameVo> positionCoursePractices = ftbCultivatePositionCoursePracticeService.listByPostLearnIdAndCourseIdsWithName(postLearnId, courseIds);
        List<FtbCultivatePositionCourseCertificateWithNameVo> positionCourseCertificates = ftbCultivatePositionCourseCertificateService.listByPostLearnIdAndCourseIdsWithName(postLearnId, courseIds);

        // 收集考试、鉴定、练习、证书ID用于批量查询用户状态
        List<String> examIds = positionCourseExams.stream()
                .map(FtbCultivatePositionCourseExamWithNameVo::getExamId)
                .distinct()
                .collect(Collectors.toList());

        List<String> identityIds = positionCourseIdentities.stream()
                .map(FtbCultivatePositionCourseIdentityWithNameVo::getIdentityId)
                .distinct()
                .collect(Collectors.toList());

        List<String> practiceIds = positionCoursePractices.stream()
                .map(FtbCultivatePositionCoursePracticeWithNameVo::getBusinessId)
                .distinct()
                .collect(Collectors.toList());

        List<String> certificateIds = positionCourseCertificates.stream()
                .map(FtbCultivatePositionCourseCertificateWithNameVo::getCertificateId)
                .distinct()
                .collect(Collectors.toList());

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

        return new RelatedDataBundle(
                positionCourseExams, positionCourseIdentities, positionCoursePractices, positionCourseCertificates,
                userExamStatusMap, userIdentificationStatusMap, userCertificateStatusMap, userSkillStatusMap, userId
        );
    }

    /**
     * 构建单个课程VO对象
     */
    private AppCultivatePositionCourseVo buildCourseVo(
            FtbCultivatePosition existingPosition,
            FtbCultivatePositionCourseWithNameVo positionCourse,
            Map<String, FtbCultivatePositionCourceLearning> learningMap,
            Map<String, List<V2ChapterVo>> learningChapterMap,
            RelatedDataBundle relatedData,
            V2CultivatePositionDetailForApp req) {
        AppCultivatePositionCourseVo courseVo = new AppCultivatePositionCourseVo();
        courseVo.convert(positionCourse);

        // 设置课程基础信息

        courseVo.setCourseName(positionCourse.getCourseName());
        courseVo.setCourseIdShow(positionCourse.getShowCourseId());


        // 设置学习状态和进度
        FtbCultivatePositionCourceLearning learningRecord = learningMap.get(positionCourse.getCourseId());
        if (learningRecord != null) {
            courseVo.setLearnState(learningRecord.getState());
            // 对于学习进度，我们暂时设为固定值，因为课程实体中没有总时长字段
            if (learningRecord.getState().equals(1)) {
                courseVo.setLearnProgress("100%"); // 在实际应用中，这里可能需要从其他地方获取进度信息
            } else if (learningRecord.getState().equals(0)) {
                courseVo.setLearnProgress("0%"); // 在实际应用中，这里可能
            } else {
                //根据已经学习的章节 和总章节计算
                List<V2ChapterVo> chapterLearningList = learningChapterMap.get(positionCourse.getCourseId());
                if (CollUtil.isEmpty(chapterLearningList)) {
                    courseVo.setLearnProgress("0%");
                } else {
                    int total = chapterLearningList.size();
                    int completed = (int) chapterLearningList.stream().filter(chapterLearning -> chapterLearning.getState().equals(1)).count();
                    courseVo.setLearnProgress(String.format("%d%%", completed * 100 / total));
                }

            }
        } else {
            courseVo.setLearnState(0); // 未学习
            courseVo.setLearnProgress("0%");
        }


        // 设置关联的考试信息
        List<AppCultivatePositionCourseExamVo> examVoList = buildExamVoList(positionCourse, relatedData, courseVo);
        courseVo.setExam(examVoList);

        // 设置关联的练习信息
        List<AppCultivatePositionCoursePracticeVo> practiceVoList = buildPracticeVoList(positionCourse, relatedData, req, courseVo);
        courseVo.setPracticeList(practiceVoList);
        Integer isCanIdentification = runCanIdentification(existingPosition, courseVo, examVoList, practiceVoList);

        //todo 查询鉴定id
        // 设置关联的鉴定信息
        List<AppCultivatePositionCourseIdentityVo> identityVoList = buildIdentityVoList(positionCourse, relatedData, isCanIdentification);
        courseVo.setIdentity(identityVoList);


        // 设置关联的证书信息
        List<AppCultivatePositionCourseCertificateVo> certificateVoList = buildCertificateVoList(positionCourse, relatedData);
        courseVo.setCertificate(certificateVoList);

        return courseVo;
    }


    private Integer runCanIdentification(FtbCultivatePosition existingPosition,
                                         AppCultivatePositionCourseVo courseVo,
                                         List<AppCultivatePositionCourseExamVo> examVoList,
                                         List<AppCultivatePositionCoursePracticeVo> practiceVoList) {
        if (!courseVo.getLearnState().equals(1)) {
            return 0;
        }
        if (existingPosition.getQualified() == 1) {

            if (CollUtil.isNotEmpty(practiceVoList)) {
                for (AppCultivatePositionCoursePracticeVo appCultivatePositionCoursePracticeVo : practiceVoList) {
                    if (appCultivatePositionCoursePracticeVo.getStatus().equals(0)) {
                        return 0;
                    }
                }
            }
            if (CollUtil.isNotEmpty(examVoList)) {
                if (!(examVoList.get(0).getExamStatus().equals(3)
                        || examVoList.get(0).getExamStatus().equals(5))) {
                    return 0;
                }
            }
        }
        return 1;
    }

    /**
     * 构建考试VO列表
     */
    private List<AppCultivatePositionCourseExamVo> buildExamVoList(FtbCultivatePositionCourseWithNameVo positionCourse, RelatedDataBundle relatedData, AppCultivatePositionCourseVo courseVo) {
        List<FtbCultivatePositionCourseExamWithNameVo> courseExams = relatedData.positionCourseExams.stream()
                .filter(exam -> exam.getCourseId().equals(positionCourse.getCourseId()))
                .filter(exam -> StringUtils.isEmpty(positionCourse.getGradeId()) || (positionCourse.getGradeId().equals(exam.getGradeId())))
                .collect(Collectors.toList());

        return courseExams.stream()
                .map(exam -> {
                    AppCultivatePositionCourseExamVo examVo = new AppCultivatePositionCourseExamVo();
                    examVo.setExamId(exam.getExamId());
                    // 直接从VO中获取考试名称，无需额外查询
                    examVo.setExamName(exam.getExamName());
                    FtbCultivateExamUser ftbCultivateExamUser = relatedData.userExamStatusMap.get(exam.getExamId());
                    if (ftbCultivateExamUser != null) {
                        examVo.setExamStatus(ftbCultivateExamUser.getStatus());
                        examVo.setUserExamId(ftbCultivateExamUser.getId());
                        examVo.setUserExamScore(ftbCultivateExamUser.getScore());
                        examVo.setExamTotalScore(ftbCultivateExamUser.getTotalScore());
                        examVo.setExamCompleteDate(ftbCultivateExamUser.getFinishTime());
                        examVo.setUserExamDuration(ftbCultivateExamUser.getDuration());
                    } else {
                        examVo.setExamStatus(0);
                        if (courseVo.getLearnState().equals(1)) {
                            String userExamId = v2CultivatePostStudyService.checkExamStatusReturnUserExamId(relatedData.userId, exam.getPostLearnId(), List.of(exam.getExamId()), relatedData.userExamStatusMap, courseVo.getCourseId(), positionCourse.getGradeId(), UserProvider.getUser().getTenantId());
                            examVo.setUserExamId(userExamId);
                        } else {
                            examVo.setUserExamId(null);
                        }
                    }
                    examVo.setLearnState(courseVo.getLearnState());
                    examVo.setCourseId(courseVo.getCourseId());
                    return examVo;
                })
                .filter(Objects::nonNull)  // 过滤掉 null 值
                .collect(Collectors.toList());
    }

    /**
     * 构建鉴定VO列表
     */
    private List<AppCultivatePositionCourseIdentityVo> buildIdentityVoList(FtbCultivatePositionCourseWithNameVo positionCourse, RelatedDataBundle relatedData, Integer isCanIdentification) {
        List<FtbCultivatePositionCourseIdentityWithNameVo> courseIdentities = relatedData.positionCourseIdentities.stream()
                .filter(identity -> identity.getCourseId().equals(positionCourse.getCourseId()))
                .filter(identity -> positionCourse.getGradeId() == null || (positionCourse.getGradeId().equals(identity.getGradeId())))
                .collect(Collectors.toList());

        return courseIdentities.stream()
                .map(identity -> {
                    AppCultivatePositionCourseIdentityVo identityVo = new AppCultivatePositionCourseIdentityVo();
                    identityVo.setIdentityId(identity.getIdentityId());
                    // 直接从VO中获取鉴定名称，无需额外查询
                    identityVo.setIdentityName(identity.getIdentityName());
                    identityVo.setBusinessSource(PositionBusinessSourceEnum.POST_LEARNING);
                    identityVo.setBusinessSourceId(identity.getPostLearnId());
                    identityVo.setIsCanIdentification(isCanIdentification);
                    CultivateIdentifyApply cultivateIdentifyApply = relatedData.userIdentificationStatusMap.get(identity.getIdentityId());
                    if (cultivateIdentifyApply != null) {
                        identityVo.setIdentificationResult(cultivateIdentifyApply.getResult());
                        identityVo.setIdentificationStatus(cultivateIdentifyApply.getStatus());
                        identityVo.setUserIdentityId(cultivateIdentifyApply.getId());
                    } else {
                        identityVo.setIdentificationResult(0);
                        identityVo.setIdentificationStatus(0);
                        identityVo.setUserIdentityId("");
                    }
                    return identityVo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 构建练习VO列表
     */
    private List<AppCultivatePositionCoursePracticeVo> buildPracticeVoList(FtbCultivatePositionCourseWithNameVo positionCourse,
                                                                           RelatedDataBundle relatedData,
                                                                           V2CultivatePositionDetailForApp req,
                                                                           AppCultivatePositionCourseVo courseVo
    ) {
        List<FtbCultivatePositionCoursePracticeWithNameVo> coursePractices = relatedData.positionCoursePractices.stream()
                .filter(practice -> practice.getCourseId().equals(positionCourse.getCourseId()))
                .filter(practice -> positionCourse.getGradeId() == null || (positionCourse.getGradeId().equals(practice.getGradeId())))
                .collect(Collectors.toList());

        return coursePractices.stream()
                .map(practice -> {
                    AppCultivatePositionCoursePracticeVo practiceVo = new AppCultivatePositionCoursePracticeVo();
                    practiceVo.setBusinessId(practice.getBusinessId());
                    practiceVo.setNum(practice.getNum());
                    // 直接从VO中获取技能点名称，无需额外查询
                    practiceVo.setBusinessName(practice.getBusinessName());
                    // 设置练习完成情况
                    List<String> completeNum = relatedData.userSkillStatusMap.get(practiceVo.getBusinessId());
                    practiceVo.setCompleteNum(completeNum != null ? completeNum.size() : 0);
                    if (practiceVo.getCompleteNum() >= practiceVo.getNum()) {
                        practiceVo.setStatus(1);
                        practiceVo.setUserPracticeIds(completeNum);
                    } else {
                        practiceVo.setStatus(0);
                    }

                    practiceVo.setLearnState(courseVo.getLearnState());
                    practiceVo.setCourseId(courseVo.getCourseId());
                    return practiceVo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 构建证书VO列表
     */
    private List<AppCultivatePositionCourseCertificateVo> buildCertificateVoList(FtbCultivatePositionCourseWithNameVo positionCourse, RelatedDataBundle relatedData) {
        List<FtbCultivatePositionCourseCertificateWithNameVo> courseCertificates = relatedData.positionCourseCertificates.stream()
                .filter(certificate -> certificate.getCourseId().equals(positionCourse.getCourseId()))
                .filter(certificate -> positionCourse.getGradeId() == null || (positionCourse.getGradeId().equals(certificate.getGradeId())))
                .collect(Collectors.toList());


        return courseCertificates.stream()
                .map(certificate -> {
                    AppCultivatePositionCourseCertificateVo certificateVo = new AppCultivatePositionCourseCertificateVo();
                    certificateVo.setCertificateId(certificate.getCertificateId());
                    // 直接从VO中获取证书名称，无需额外查询
                    certificateVo.setCertificateName(certificate.getCertificateName());
                    Boolean isGetCertificate = v2CultivatePostStudyService.checkIsTriggerPositionCertificate(relatedData.userId, certificate.getCertificateId(), certificate.getPostLearnId(), certificate.getPostRankId(), StringUtils.isEmpty(certificate.getGradeId()) ? "" : certificate.getGradeId(), positionCourse.getCourseId());
                    certificateVo.setIsGet(isGetCertificate);
                    FtbCertificateUserEntity ftbCertificateUserEntity = relatedData.userCertificateStatusMap.get(certificate.getCertificateId());
                    if (ftbCertificateUserEntity != null) {
                        certificateVo.setUserCertificateId(ftbCertificateUserEntity.getId());
                        certificateVo.setUserCertificateStatus(ftbCertificateUserEntity.getStatus());
                    }
                    return certificateVo;
                })
                .collect(Collectors.toList());
    }

    /**
     * 内部类：封装课程关联的所有相关数据
     */
    private static class RelatedDataBundle {
        List<FtbCultivatePositionCourseExamWithNameVo> positionCourseExams;
        List<FtbCultivatePositionCourseIdentityWithNameVo> positionCourseIdentities;
        List<FtbCultivatePositionCoursePracticeWithNameVo> positionCoursePractices;
        List<FtbCultivatePositionCourseCertificateWithNameVo> positionCourseCertificates;

        // 基础信息已通过JOIN查询包含在上面的VO中，不再需要单独的Map

        Map<String, FtbCultivateExamUser> userExamStatusMap;
        Map<String, CultivateIdentifyApply> userIdentificationStatusMap;
        Map<String, FtbCertificateUserEntity> userCertificateStatusMap;
        Map<String, List<String>> userSkillStatusMap;
        String userId;

        public RelatedDataBundle(
                List<FtbCultivatePositionCourseExamWithNameVo> positionCourseExams,
                List<FtbCultivatePositionCourseIdentityWithNameVo> positionCourseIdentities,
                List<FtbCultivatePositionCoursePracticeWithNameVo> positionCoursePractices,
                List<FtbCultivatePositionCourseCertificateWithNameVo> positionCourseCertificates,
                Map<String, FtbCultivateExamUser> userExamStatusMap,
                Map<String, CultivateIdentifyApply> userIdentificationStatusMap,
                Map<String, FtbCertificateUserEntity> userCertificateStatusMap,
                Map<String, List<String>> userSkillStatusMap,
                String userId) {
            this.positionCourseExams = positionCourseExams;
            this.positionCourseIdentities = positionCourseIdentities;
            this.positionCoursePractices = positionCoursePractices;
            this.positionCourseCertificates = positionCourseCertificates;
            this.userExamStatusMap = userExamStatusMap;
            this.userIdentificationStatusMap = userIdentificationStatusMap;
            this.userCertificateStatusMap = userCertificateStatusMap;
            this.userSkillStatusMap = userSkillStatusMap;
            this.userId = userId;
        }
    }

    @Override
    public Page<V2CultivateJobLearnCourseVo> positionCourseList(V2CultivateCoursePageReq req) {

        Page<V2CultivateJobLearnCourseVo> page = Page.of(req.getCurrentPage(), req.getPageSize());
        return ftbCultivateCourseMapper.queryBindingCourses(page, req);
    }


    @Override
    public Boolean checkExist(String postId) {
        LambdaQueryWrapper<FtbCultivatePosition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(FtbCultivatePosition::getPostId, postId);
        queryWrapper.eq(FtbCultivatePosition::getIsGrounding, 1);
        queryWrapper.eq(FtbCultivatePosition::getEnabledMark, 0); // 查询未被删除的记录
        long count = ftbCultivatePositionMapper.selectCount(queryWrapper);
        return count > 0;
    }

    @Override
    public List<AppCourseSimpleVo> otherPositionCourseList(V2OtherCultivatePositionCourseForAppReq req, CultivatePage page) {
        UserBoundVO userBoundVO = getUserBoundVO(req);

        // 2. 查询用户岗位ID
        String postId = userBoundVO.getPositionId();
        //用户的职级id
        String gradeId = userBoundVO.getGradeId();

        List<AppCourseSimpleVo> list = ftbCultivatePositionCourseService.queryAllPositionLearnCourseLists(req);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        list = filterOtherPositionList(list, postId, gradeId);
        if (StringUtils.isNotEmpty(req.getPostId())) {
            list = filterSearchPostAndGrade(list, req.getPostId(), req.getGradeId());
        }
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        //获取岗位ids 和 gradeIds
        List<String> postIds = new ArrayList<>();
        List<String> gradeIds = new ArrayList<>();
        List<String> courseIds = new ArrayList<>();
        for (AppCourseSimpleVo vo : list) {
            postIds.add(vo.getPostId());
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                gradeIds.add(vo.getGradeId());
            }
            courseIds.add(vo.getCourseId());
        }
        //批量查询岗位名称
        Map<String, PositionVO> stringPositionVOMap = userApiV2Util.listPositionDetailInfoByIdsReturnMap(postIds, null);
        Map<String, GradeVO> stringGradeVOMap = userApiV2Util.listGradeByIdsReturnMap(gradeIds, null);

        Map<String, Long> studyNumMap = v2CultivateBatchQueryService.batchQueryCourseLearningCount(courseIds);
        Map<String, FtbCultivatePositionCourceLearning> learningStateMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnStatus(userBoundVO.getId(), courseIds);


        for (AppCourseSimpleVo vo : list) {
            vo.setLearnTotalNumber(studyNumMap.getOrDefault(vo.getCourseId(), 0L));
            PositionVO positionVO = stringPositionVOMap.get(vo.getPostId());
            if (positionVO != null) {
                vo.setPostName(positionVO.getFullName());
            }
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                GradeVO gradeVO = stringGradeVOMap.get(vo.getGradeId());
                if (gradeVO != null) {
                    vo.setGradeName(gradeVO.getFullName());
                }
            }
            FtbCultivatePositionCourceLearning state = learningStateMap.get(vo.getCourseId());
            if (state == null) {
                vo.setLearnState(0); // 未学习
            } else {
                vo.setLearnState(state.getState()); // 0未学习，1已学习，2学习中
            }
        }
        return list;

    }

    @Override
    public Page<AppCourseSimpleVo> allCompleteCourseLists(V2NextUserCultivateCourseListReq req) {

        List<String> courseIds = queryAllCourseIdsForPromotion(req.getUserId(), req.getPromotionId());
        if (CollUtil.isEmpty(courseIds)) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        return ftbCultivatePositionMapper.allCompleteCourseLists(Page.of(req.getCurrentPage(), req.getPageSize()), req, courseIds);
    }

    @Override
    public Page<AppCultivateCourseExamVo> allCompleteExamLists(V2NextUserCultivateCourseListReq req) {

        List<String> examIds = queryAllExamIdsForPromotion(req.getUserId(), req.getPromotionId());
        if (CollUtil.isEmpty(examIds)) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        return ftbCultivatePositionMapper.allCompleteExamLists(Page.of(req.getCurrentPage(), req.getPageSize()), req, examIds);
    }

    @Override
    public Page<AppCultivateCourseIdentityVo> allCompleteIdentityLists(V2NextUserCultivateCourseListReq req) {

        NextUserAppIdentityTmpVo vo = queryAllIdentityIdsForPromotion(req.getUserId(), req.getPromotionId());
        if (CollUtil.isEmpty(vo.getIdentityIds()) || CollUtil.isEmpty(vo.getPositionLearnIds())) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        return ftbCultivatePositionMapper.allCompleteIdentityLists(Page.of(req.getCurrentPage(), req.getPageSize()), req, vo.getIdentityIds(), vo.getPositionLearnIds());

    }

    @Override
    public PageListVO<AppPracticeCountVo> allCompletePracticeLists(V2NextUserCultivateCourseListReq req) {
        List<String> practiceIds = queryAllPracticeIdsForPromotion(req.getUserId(), req.getPromotionId());
        if (CollUtil.isEmpty(practiceIds)) {
            return UserApiV2Util.returnEmptyListGeneric(req.getCurrentPage(), req.getPageSize());
        }
        Map<String, Integer> practiceCountMap = new HashMap<>();
        for (String practiceId : practiceIds) {
            String[] split = practiceId.split("_");
            practiceCountMap.put(split[0], Integer.parseInt(split[1]));
        }
        List<AppPracticeCountVo> appPracticeCountVos = ftbCultivatePositionMapper.allCompletePracticeLists(req, new ArrayList<>(practiceCountMap.keySet()));
        if (CollUtil.isEmpty(appPracticeCountVos)) {
            return UserApiV2Util.returnEmptyListGeneric(req.getCurrentPage(), req.getPageSize());
        }
        List<AppPracticeCountVo> ret = new ArrayList<>();
        for (AppPracticeCountVo vo : appPracticeCountVos) {
            Integer i = practiceCountMap.get(vo.getId());
            if (vo.getNum() >= i) {
                vo.setStatus(1);
                ret.add(vo);
            }
        }
        return UserApiV2Util.buildPage(ret, req.getPageSize(), req.getCurrentPage());

    }

    private List<String> queryAllPracticeIdsForPromotion(String userId, String promotionId) {
        LambdaQueryWrapper<FtbCultivatePromotionMemberNew> memberWrapper = Wrappers.lambdaQuery();
        memberWrapper.eq(FtbCultivatePromotionMemberNew::getPromotionId, promotionId)
                .eq(FtbCultivatePromotionMemberNew::getUserId, userId)
                .eq(FtbCultivatePromotionMemberNew::getDeleteMark, 0); // 只查询未删除的记录
        List<FtbCultivatePromotionMemberNew> memberNewList = ftbCultivatePromotionMemberNewMapper.selectList(memberWrapper);
        if (CollUtil.isEmpty(memberNewList)) {
            return new ArrayList<>();
        }

        //查询所有的岗位学习课程列表
        List<FtbCultivatePositionCoursePractice> AllPracticeList = ftbCultivatePositionCoursePracticeService.queryAllPositionLearnParacticeLists(new V2OtherCultivatePositionCourseForAppReq());
        if (CollUtil.isEmpty(AllPracticeList)) {
            return new ArrayList<>();
        }
        Map<String, List<String>> positionToPractice = new HashMap<>();
        for (FtbCultivatePositionCoursePractice vo : AllPracticeList) {
            String key = vo.getPostRankId();
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                key = key + "_" + vo.getGradeId();
            }
            if (positionToPractice.containsKey(key)) {
                positionToPractice.get(key).add(vo.getBusinessId() + "_" + vo.getNum());
            } else {
                List<String> ids = new ArrayList<>();
                ids.add(vo.getBusinessId() + "_" + vo.getNum());
                positionToPractice.put(key, ids);
            }
        }

        List<String> allPracticeIds = new ArrayList<>();
        for (FtbCultivatePromotionMemberNew memberNew : memberNewList) {
            String key = memberNew.getPositionId();
            if (StringUtils.isNotEmpty(memberNew.getGradeId())) {
                key = key + "_" + memberNew.getGradeId();
            }
            List<String> ids = positionToPractice.get(key);
            if (CollUtil.isNotEmpty(ids)) {
                allPracticeIds.addAll(ids);
            }
        }
        return allPracticeIds;
    }

    private NextUserAppIdentityTmpVo queryAllIdentityIdsForPromotion(String userId, String promotionId) {
        NextUserAppIdentityTmpVo tmpVo = new NextUserAppIdentityTmpVo();
        LambdaQueryWrapper<FtbCultivatePromotionMemberNew> memberWrapper = Wrappers.lambdaQuery();
        memberWrapper.eq(FtbCultivatePromotionMemberNew::getPromotionId, promotionId)
                .eq(FtbCultivatePromotionMemberNew::getUserId, userId)
                .eq(FtbCultivatePromotionMemberNew::getDeleteMark, 0); // 只查询未删除的记录
        List<FtbCultivatePromotionMemberNew> memberNewList = ftbCultivatePromotionMemberNewMapper.selectList(memberWrapper);
        if (CollUtil.isEmpty(memberNewList)) {
            return tmpVo;
        }

        //查询所有的岗位学习课程列表
        List<FtbCultivatePositionCourseIdentity> allIdentityList = ftbCultivatePositionCourseIdentityService.queryAllPositionLearnIdentityLists();
        if (CollUtil.isEmpty(allIdentityList)) {
            return tmpVo;
        }
        Map<String, List<String>> positionToIdentity = new HashMap<>();
        for (FtbCultivatePositionCourseIdentity vo : allIdentityList) {
            String key = vo.getPostRankId();
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                key = key + "_" + vo.getGradeId();
            }
            if (positionToIdentity.containsKey(key)) {
                positionToIdentity.get(key).add(vo.getIdentityId());
            } else {
                List<String> identityIds = new ArrayList<>();
                identityIds.add(vo.getIdentityId());
                positionToIdentity.put(key, identityIds);
            }
        }

        List<String> allIdentityIds = new ArrayList<>();
        for (FtbCultivatePromotionMemberNew memberNew : memberNewList) {
            String key = memberNew.getPositionId();
            if (StringUtils.isNotEmpty(memberNew.getGradeId())) {
                key = key + "_" + memberNew.getGradeId();
            }
            List<String> identityIds = positionToIdentity.get(key);
            if (CollUtil.isNotEmpty(identityIds)) {
                allIdentityIds.addAll(identityIds);
            }
        }
        Set<String> positionIds = memberNewList.stream().map(FtbCultivatePromotionMemberNew::getPositionId).collect(Collectors.toSet());
        tmpVo.setPositionLearnIds(convertLearnIngId(positionIds));
        tmpVo.setIdentityIds(allIdentityIds);
        return tmpVo;
    }

    private List<String> convertLearnIngId(Set<String> positionIds) {
        LambdaQueryWrapper<FtbCultivatePosition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.in(FtbCultivatePosition::getPostId, positionIds);
        queryWrapper.eq(FtbCultivatePosition::getIsGrounding, 1);
        queryWrapper.eq(FtbCultivatePosition::getEnabledMark, 0); // 查询未被删除的记录
        List<FtbCultivatePosition> ftbCultivatePositions = ftbCultivatePositionMapper.selectList(queryWrapper);
        if (CollUtil.isEmpty(ftbCultivatePositions)) {
            return new ArrayList<>();
        }
        return ftbCultivatePositions.stream().map(FtbCultivatePosition::getId).collect(Collectors.toList());
    }

    private List<String> queryAllExamIdsForPromotion(String userId, String promotionId) {
        LambdaQueryWrapper<FtbCultivatePromotionMemberNew> memberWrapper = Wrappers.lambdaQuery();
        memberWrapper.eq(FtbCultivatePromotionMemberNew::getPromotionId, promotionId)
                .eq(FtbCultivatePromotionMemberNew::getUserId, userId)
                .eq(FtbCultivatePromotionMemberNew::getDeleteMark, 0); // 只查询未删除的记录
        List<FtbCultivatePromotionMemberNew> memberNewList = ftbCultivatePromotionMemberNewMapper.selectList(memberWrapper);
        if (CollUtil.isEmpty(memberNewList)) {
            return new ArrayList<>();
        }

        //查询所有的岗位学习课程列表
        List<FtbCultivatePositionCourseExam> AllExamList = ftbCultivatePositionCourseExamService.queryAllPositionLearnExamLists(new V2OtherCultivatePositionCourseForAppReq());
        if (CollUtil.isEmpty(AllExamList)) {
            return new ArrayList<>();
        }
        Map<String, List<String>> positionToExam = new HashMap<>();
        for (FtbCultivatePositionCourseExam vo : AllExamList) {
            String key = vo.getPostRankId();
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                key = key + "_" + vo.getGradeId();
            }
            if (positionToExam.containsKey(key)) {
                positionToExam.get(key).add(vo.getExamId());
            } else {
                List<String> examIds = new ArrayList<>();
                examIds.add(vo.getExamId());
                positionToExam.put(key, examIds);
            }
        }

        List<String> allExamIds = new ArrayList<>();
        for (FtbCultivatePromotionMemberNew memberNew : memberNewList) {
            String key = memberNew.getPositionId();
            if (StringUtils.isNotEmpty(memberNew.getGradeId())) {
                key = key + "_" + memberNew.getGradeId();
            }
            List<String> examIds = positionToExam.get(key);
            if (CollUtil.isNotEmpty(examIds)) {
                allExamIds.addAll(examIds);
            }
        }
        return allExamIds;
    }

    private List<String> queryAllCourseIdsForPromotion(String userId, String promotionId) {
        LambdaQueryWrapper<FtbCultivatePromotionMemberNew> memberWrapper = Wrappers.lambdaQuery();
        memberWrapper.eq(FtbCultivatePromotionMemberNew::getPromotionId, promotionId)
                .eq(FtbCultivatePromotionMemberNew::getUserId, userId)
                .eq(FtbCultivatePromotionMemberNew::getDeleteMark, 0); // 只查询未删除的记录
        List<FtbCultivatePromotionMemberNew> memberNewList = ftbCultivatePromotionMemberNewMapper.selectList(memberWrapper);
        if (CollUtil.isEmpty(memberNewList)) {
            return new ArrayList<>();
        }

        //查询所有的岗位学习课程列表
        List<AppCourseSimpleVo> AllCourseList = ftbCultivatePositionCourseService.queryAllPositionLearnCourseLists(new V2OtherCultivatePositionCourseForAppReq());
        if (CollUtil.isEmpty(AllCourseList)) {
            return new ArrayList<>();
        }
        Map<String, List<String>> positionToCourse = new HashMap<>();
        for (AppCourseSimpleVo vo : AllCourseList) {
            String key = vo.getPostId();
            if (StringUtils.isNotEmpty(vo.getGradeId())) {
                key = key + "_" + vo.getGradeId();
            }
            if (positionToCourse.containsKey(key)) {
                positionToCourse.get(key).add(vo.getCourseId());
            } else {
                List<String> courseIds = new ArrayList<>();
                courseIds.add(vo.getCourseId());
                positionToCourse.put(key, courseIds);
            }
        }

        List<String> allCourseIds = new ArrayList<>();
        for (FtbCultivatePromotionMemberNew memberNew : memberNewList) {
            String key = memberNew.getPositionId();
            if (StringUtils.isNotEmpty(memberNew.getGradeId())) {
                key = key + "_" + memberNew.getGradeId();
            }
            List<String> courseIds = positionToCourse.get(key);
            if (CollUtil.isNotEmpty(courseIds)) {
                allCourseIds.addAll(courseIds);
            }
        }
        return allCourseIds;
    }


    private List<AppCourseSimpleVo> filterSearchPostAndGrade(List<AppCourseSimpleVo> lists, String postId, String gradeId) {
        List<AppCourseSimpleVo> returnList = new ArrayList<>();
        for (AppCourseSimpleVo vo : lists) {
            if (StringUtils.isEmpty(gradeId)) {
                if (vo.getPostId().equals(postId)) {
                    returnList.add(vo);
                }
            } else {
                if (vo.getPostId().equals(postId) && vo.getGradeId().equals(gradeId)) {
                    returnList.add(vo);
                }
            }
        }
        return returnList;
    }


    @Override
    public Page<AppCourseSimpleVo> selfPositionAllCompleteCourseLists(V2NextUserCultivateCourseListReq req) {
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (userPrimaryBoundOne == null || StringUtils.isEmpty(userPrimaryBoundOne.getPositionId())) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        String positionId = userPrimaryBoundOne.getPositionId();
        String gradeId = userPrimaryBoundOne.getGradeId();
        // 3. 查询岗位学习是否存在
        FtbCultivatePosition cultivatePosition = getFtbCultivatePosition(positionId);

        if (cultivatePosition == null) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        List<String> ids = new ArrayList<>();
        if (cultivatePosition.getIsConfiguredToGrade().equals(0))//未分配到职级
        {
            //根据岗位id查询课程列表
            ids = queryPositionBindItem(cultivatePosition, CultivateTypeEnum.COURSE, "");
        } else {
            if (StringUtils.isNotEmpty(gradeId)) {
                //根据岗位id和职级id查询课程列表
                ids = queryPositionBindItem(cultivatePosition, CultivateTypeEnum.COURSE, gradeId);
            }
        }

        if (CollUtil.isEmpty(ids)) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        return ftbCultivatePositionMapper.allCompleteCourseLists(Page.of(req.getCurrentPage(), req.getPageSize()), req, ids);
    }

    private FtbCultivatePosition getFtbCultivatePosition(String positionId) {
        return ftbCultivatePositionMapper.selectOne(
                Wrappers.<FtbCultivatePosition>lambdaQuery()
                        .eq(FtbCultivatePosition::getPostId, positionId)
                        .eq(FtbCultivatePosition::getIsGrounding, 1)
                        .eq(FtbCultivatePosition::getEnabledMark, 0)
        );
    }

    @Override
    public Page<AppCultivateCourseExamVo> selfPositionAllCompleteExamLists(V2NextUserCultivateCourseListReq req) {
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (userPrimaryBoundOne == null || StringUtils.isEmpty(userPrimaryBoundOne.getPositionId())) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        String positionId = userPrimaryBoundOne.getPositionId();
        String gradeId = userPrimaryBoundOne.getGradeId();
        // 3. 查询岗位学习是否存在
        FtbCultivatePosition cultivatePosition = getFtbCultivatePosition(positionId);

        if (cultivatePosition == null) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        List<String> ids = new ArrayList<>();
        if (cultivatePosition.getIsConfiguredToGrade().equals(0))//未分配到职级
        {
            //根据岗位id查询课程列表
            ids = queryPositionBindItem(cultivatePosition, CultivateTypeEnum.EXAM, "");
        } else {
            if (StringUtils.isNotEmpty(gradeId)) {
                //根据岗位id和职级id查询课程列表
                ids = queryPositionBindItem(cultivatePosition, CultivateTypeEnum.EXAM, gradeId);
            }
        }

        if (CollUtil.isEmpty(ids)) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }

        return ftbCultivatePositionMapper.allCompleteExamLists(Page.of(req.getCurrentPage(), req.getPageSize()), req, ids);
    }

    @Override
    public Page<AppCultivateCourseIdentityVo> selfPositionAllCompleteIdentityLists(V2NextUserCultivateCourseListReq req) {
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (userPrimaryBoundOne == null || StringUtils.isEmpty(userPrimaryBoundOne.getPositionId())) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        String positionId = userPrimaryBoundOne.getPositionId();
        String gradeId = userPrimaryBoundOne.getGradeId();
        // 3. 查询岗位学习是否存在
        FtbCultivatePosition cultivatePosition = getFtbCultivatePosition(positionId);

        if (cultivatePosition == null) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        List<String> ids = new ArrayList<>();
        if (cultivatePosition.getIsConfiguredToGrade().equals(0))//未分配到职级
        {
            //根据岗位id查询课程列表
            ids = queryPositionBindItem(cultivatePosition, CultivateTypeEnum.IDENTITY, "");
        } else {
            if (StringUtils.isNotEmpty(gradeId)) {
                //根据岗位id和职级id查询课程列表
                ids = queryPositionBindItem(cultivatePosition, CultivateTypeEnum.IDENTITY, gradeId);
            }
        }

        if (CollUtil.isEmpty(ids)) {
            return Page.of(req.getCurrentPage(), req.getPageSize());
        }
        return ftbCultivatePositionMapper.allCompleteIdentityLists(Page.of(req.getCurrentPage(), req.getPageSize()), req, ids, List.of(positionId));
    }

    @Override
    public PageListVO<AppPracticeCountVo> selfPositionAllCompletePracticeLists(V2NextUserCultivateCourseListReq req) {
        UserBoundVO userPrimaryBoundOne = userApiV2Util.getUserPrimaryBoundOne(req.getUserId(), null);
        if (userPrimaryBoundOne == null || StringUtils.isEmpty(userPrimaryBoundOne.getPositionId())) {
            return UserApiV2Util.returnEmptyListGeneric(req.getCurrentPage(), req.getPageSize());
        }
        String positionId = userPrimaryBoundOne.getPositionId();
        String gradeId = userPrimaryBoundOne.getGradeId();
        // 3. 查询岗位学习是否存在
        FtbCultivatePosition cultivatePosition = getFtbCultivatePosition(positionId);

        if (cultivatePosition == null) {
            return UserApiV2Util.returnEmptyListGeneric(req.getCurrentPage(), req.getPageSize());
        }

        List<FtbCultivatePositionCoursePractice> positionCoursePractices = new ArrayList<>();
        if (cultivatePosition.getIsConfiguredToGrade().equals(0))//未分配到职级
        {
            //根据岗位id查询课程列表
            positionCoursePractices = ftbCultivatePositionCoursePracticeService.queryPositionBindItem(cultivatePosition, "");
        } else {
            if (StringUtils.isNotEmpty(gradeId)) {
                //根据岗位id和职级id查询课程列表
                positionCoursePractices = ftbCultivatePositionCoursePracticeService.queryPositionBindItem(cultivatePosition, gradeId);
            }
        }

        if (CollUtil.isEmpty(positionCoursePractices)) {
            return UserApiV2Util.returnEmptyListGeneric(req.getCurrentPage(), req.getPageSize());
        }


        List<AppPracticeCountVo> appPracticeCountVos = ftbCultivatePositionMapper.allCompletePracticeLists(req, positionCoursePractices.stream().map(FtbCultivatePositionCoursePractice::getBusinessId).collect(Collectors.toList()));
        if (CollUtil.isEmpty(appPracticeCountVos)) {
            return UserApiV2Util.returnEmptyListGeneric(req.getCurrentPage(), req.getPageSize());
        }
        Map<String, FtbCultivatePositionCoursePractice> map = new HashMap<>();
        for (FtbCultivatePositionCoursePractice positionCoursePractice : positionCoursePractices) {
            map.put(positionCoursePractice.getBusinessId(), positionCoursePractice);
        }
        appPracticeCountVos = appPracticeCountVos.stream().filter(vo -> vo.getNum() > 0).collect(Collectors.toList());
        List<AppPracticeCountVo> ret = new ArrayList<>();
        for (AppPracticeCountVo vo : appPracticeCountVos) {
            FtbCultivatePositionCoursePractice practice = map.get(vo.getId());
            if (vo.getNum() >= practice.getNum()) {
                vo.setStatus(1);
                ret.add(vo);
            }
        }
        return UserApiV2Util.buildPage(ret, req.getPageSize(), req.getCurrentPage());
    }

    private List<String> queryPositionBindItem(FtbCultivatePosition cultivatePosition, CultivateTypeEnum typeEnum, String gradeId) {
        switch (typeEnum) {
            case COURSE:
                return ftbCultivatePositionCourseService.queryPositionBindItem(cultivatePosition, gradeId);
            case EXAM:
                return ftbCultivatePositionCourseExamService.queryPositionBindItem(cultivatePosition, gradeId);
            case IDENTITY:
                return ftbCultivatePositionCourseIdentityService.queryPositionBindItem(cultivatePosition, gradeId);
            default:
                return new ArrayList<>();
        }
    }

    /**
     * 检查考试是否被岗位学习绑定
     *
     * @param examId 考试ID
     * @return true-已绑定 false-未绑定
     */
    @Override
    public Boolean checkExamBinding(String examId) {
        return ftbCultivatePositionCourseExamService.checkExamBinding(examId);
    }

    public static final class PositionConstants {
        public static final int ENABLED_MARK_VALID = 0;
        public static final int ENABLED_MARK_DELETED = 1;
        public static final int IS_GROUNDING_ONLINE = 1;
        public static final int IS_GROUNDING_OFFLINE = 0;
        public static final long DEFAULT_COUNT = 0L;
        public static final int LEARN_STATE_NOT_STARTED = 0;
        public static final int LEARN_STATE_COMPLETED = 1;
        public static final int LEARN_STATE_IN_PROGRESS = 2;
        public static final int DEFAULT_SORT_CODE = 0;
    }

}