package jnpf.cultivate.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import jnpf.base.UserInfo;
import jnpf.base.vo.PageListVO;
import jnpf.base.vo.PaginationVO;
import jnpf.cultivate.mapper.FtbCultivatePositionStatisticesMapper;
import jnpf.cultivate.service.FtbCultivateExamUserService;
import jnpf.cultivate.service.FtbCultivatePositionStatisticesService;
import jnpf.cultivate.service.FtbCultivatePromotionNewService;
import jnpf.cultivate.utils.CultivatePerUtils;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.cultivate.v2.service.V2CultivateBatchQueryService;
import jnpf.database.util.TenantDataSourceUtil;
import jnpf.exception.LoginException;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.cultivate.dto.position.FtbCultivatePersonStatisticesDTO;
import jnpf.model.cultivate.dto.position.FtbCultivatePositionOrgStatisticesDTO;
import jnpf.model.cultivate.dto.position.FtbCultivatePositionPersonStatisticesDTO;
import jnpf.model.cultivate.resp.ExamCultivateForPositionVo;
import jnpf.model.cultivate.v2.position.vo.CultivatePositionCourseVo;
import jnpf.model.cultivate.v2.position.vo.CultivateUserPositionVo;
import jnpf.model.cultivate.v2.position.vo.PersonForLeaderVo;
import jnpf.model.cultivate.v2.position.vo.V2StudyCountVo;
import jnpf.model.cultivate.v2.statistics.V2UserCourseStudyVo;
import jnpf.model.cultivate.vo.common.InnerPowerUserVO;
import jnpf.model.cultivate.vo.course.web.UserCourseStudyVo;
import jnpf.model.cultivate.vo.position.*;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.model.personnels.po.FtbPersonnelsStaffRoster;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.vo.v2.organzie.OrganizeFullBasicVO;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.position.PositionAndGradesVO;
import jnpf.permission.vo.v2.position.PositionVO;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.permission.vo.v2.user.UserPageListVO;
import jnpf.permission.vo.v2.user.UserRelationBaseVO;
import jnpf.personnels.service.FtbPersonnelsStaffRosterService;
import jnpf.util.Constants;
import jnpf.util.UserProvider;
import jnpf.util.data.DataSourceContextHolder;
import jnpf.utils.FeignHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Slf4j
@Service
public class FtbCultivatePositionStatisticesServiceImpl implements FtbCultivatePositionStatisticesService {

    @Resource
    private FtbCultivatePositionStatisticesMapper ftbCultivatePositionStatisticesMapper;

    @Resource
    private FtbPersonnelsStaffRosterService ftbPersonnelsStaffRosterService;

    @Autowired
    private UserApiV2Util userApiV2Util;


    @Resource
    private FtbCultivateExamUserService ftbCultivateExamUserService;

    @Autowired
    private CultivatePerUtils cultivatePerUtils;

    @Resource
    private FtbCultivatePromotionNewService ftbCultivatePromotionNewService;

    @Resource(name = "threadPoolTaskExecutor")
    ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private V2CultivateBatchQueryService v2CultivateBatchQueryService;


    /**
     * 返回一个空的分页结果列表
     *
     * @param statisticDTO 统计查询参数DTO
     * @return 空的分页结果列表
     */
    private PageListVO<FtbCultivatePositionOrgStatisticesVO> returnEmptyList(FtbCultivatePositionOrgStatisticesDTO statisticDTO) {
        PageListVO<FtbCultivatePositionOrgStatisticesVO> pageInfo = new PageListVO<>();
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(statisticDTO.getCurrentPage());
        pagination.setPageSize(statisticDTO.getPageSize());
        pagination.setTotal(0);
        pageInfo.setList(new ArrayList<>());
        pageInfo.setPagination(pagination);
        return pageInfo;
    }

    @Override
    public PageListVO<FtbCultivatePositionOrgStatisticesVO> organizationListStatistics(FtbCultivatePositionOrgStatisticesDTO statisticDTO) {
        Page<FtbCultivatePositionOrgStatisticesVO> page = statisticDTO.coverCultivatePage();
        // 多选组织情况 根据每一个组织维度统计
        List<String> orgIds = new ArrayList<>();
        List<String> powerOrgList = userApiV2Util.queryPowerOrgList();
        if (CollUtil.isEmpty(powerOrgList)) {
            return returnEmptyList(statisticDTO);
        }
        // 勾选
        if ("1".equals(statisticDTO.getSelectLogo()) && CollUtil.isNotEmpty(statisticDTO.getOrgId())) {
            List<String> allOrg = new ArrayList<>(statisticDTO.getOrgId());
            List<String> allOrganize = cultivatePerUtils.getAllOrganizationInformation(statisticDTO.getOrgId());
            if (CollUtil.isNotEmpty(allOrganize)) {
                allOrg.addAll(allOrganize);
            }
            List<String> intersection = UserApiV2Util.getIntersection(powerOrgList, allOrg);
            if (CollUtil.isNotEmpty(intersection)) {
                orgIds = (intersection);
            } else {
                return returnEmptyList(statisticDTO);
            }
        } else if (CollUtil.isNotEmpty(statisticDTO.getOrgId())) {
            List<String> intersection = UserApiV2Util.getIntersection(powerOrgList, statisticDTO.getOrgId());
            if (CollUtil.isNotEmpty(intersection)) {
                orgIds = intersection;
            } else {
                return returnEmptyList(statisticDTO);
            }
        } else {
            orgIds = powerOrgList;
        }
        if (StrUtil.isNotEmpty(statisticDTO.getOrgIds())) {
            List<OrganizeGeneralDetailVO> organizeGeneralDetailVOS = userApiV2Util.organizesOrHaveChildByOrganizeEncodes(Arrays.asList(statisticDTO.getOrgIds().split(",")), null);
            if (CollUtil.isEmpty(organizeGeneralDetailVOS)) {
                return returnEmptyList(statisticDTO);
            }
            List<String> intersection = UserApiV2Util.getIntersection(orgIds, organizeGeneralDetailVOS.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            if (CollUtil.isEmpty(intersection)) {
                return returnEmptyList(statisticDTO);
            }
            orgIds = intersection;
        }
        // 默认情况
        String orgIdBySpecial = statisticDTO.getOrgIdBySpecial();
        if (StringUtils.isNotEmpty(orgIdBySpecial) && !orgIds.contains(orgIdBySpecial)) {
            orgIds.add(orgIdBySpecial);
        }

        orgIds = UserApiV2Util.uniqueStringList(orgIds);
//        List<OrganizeEntity> organizeEntityList = organizeApi.getOrganizeByIds(orgIds);
        List<OrganizeGeneralDetailVO> organizeEntityList = userApiV2Util.organizesByOrganizeIds(orgIds, null);
        orgIds = new ArrayList<>();
        for (OrganizeGeneralDetailVO organizeGeneralDetailVO : organizeEntityList) {
            if (!organizeGeneralDetailVO.getOrganizeCategoryEnums().equals(OrganizeCategoryEnums.TEAM)) {
                orgIds.add(organizeGeneralDetailVO.getId());
            }
        }

        Map<String, OrganizeGeneralDetailVO> orgMap = organizeEntityList.stream().collect(Collectors.toMap(OrganizeGeneralDetailVO::getId, v -> v));
//        Map<String, String> orgIdMap = cultivatePerUtils.convertOrganizationalId(orgIds);
        // 批量统计对应查询组织下人数
//        Map<String, Long> listFeignMap = organizeApi.batchOrganizeUsersCount(orgIds);
        List<UserPageListVO> userList = userApiV2Util.getUserListForOrgIds(orgIds, null);
        Map<String, Long> listFeignMap = userApiV2Util.convertUserCount(userList);
        // 根据组织查询岗位
//        Map<String, List<String>> batchListByOrganizeIds = positionApi.batchListByOrganizeIds(orgIds);
        Map<String, List<String>> batchListByOrganizeIds = userApiV2Util.listPositionBaseInfoByIdsReturnMapSimple(orgIds, null);


        // 根据组织查询组织下的人
//        Map<String, List<String>> orgUserRelationMap = userApi.batchGetAllUser(orgIds);
        Map<String, List<String>> orgUserRelationMap = userApiV2Util.convertUserIdList(userList);
        UserInfo user = UserProvider.getUser();
        String tenantId = user.getTenantId();
        // 分块处理数据
        List<List<String>> partition = new ArrayList<>();
        if (orgIds.size() > 1000) {
            partition = Lists.partition(orgIds, 10);
        } else if (500 < orgIds.size() && orgIds.size() < 1000) {
            partition = Lists.partition(orgIds, 5);
        } else {
            partition = Lists.partition(orgIds, 1);
        }
        List<CompletableFuture<List<FtbCultivatePositionOrgStatisticesVO>>> futures = new ArrayList<>();
        // 多线程分块处理
        // 课程总数
        Integer totalNumberOfCourses = ftbCultivatePositionStatisticesMapper.totalNumberOfCourses();
        for (List<String> listOrg : partition) {
            futures.add(CompletableFuture.supplyAsync(() -> {
                return listOrg.parallelStream().map(orgId -> {
                    try {
                        TenantDataSourceUtil.switchTenant(tenantId);
                    } catch (LoginException e) {
                        throw new RuntimeException(e);
                    }
                    FtbCultivatePositionOrgStatisticesVO freightCultivate = new FtbCultivatePositionOrgStatisticesVO();
                    if (listFeignMap.containsKey(orgId)) {
                        Long data = listFeignMap.get(orgId);
                        // 组织人数
                        freightCultivate.setNumberOfPeopleInTheOrganization(data);
                    }
                    // 组织名称和组织id
                    freightCultivate.setOrgId(orgId);
                    OrganizeGeneralDetailVO organizeGeneralDetailVO = orgMap.get(orgId);
                    if (organizeGeneralDetailVO != null) {
                        freightCultivate.setOrganizationCustomId(organizeGeneralDetailVO.getEnCode());
                        freightCultivate.setNameOfAssociation(organizeGeneralDetailVO.getName());
                    }
                    List<String> userIds = null;
                    if (orgUserRelationMap.containsKey(orgId)) {
                        userIds = orgUserRelationMap.get(orgId);
                    }
                    if (CollUtil.isNotEmpty(userIds)) {
                        String postionIds = "-1";
                        if (batchListByOrganizeIds.containsKey(orgId))
                            postionIds = batchListByOrganizeIds.get(orgId).stream()
                                    .collect(Collectors.joining(","));
                        // 参与学习人数
                        List<String> numberOfPeopleParticipatingInTheStudy = ftbCultivatePositionStatisticesMapper.numberOfPeopleParticipatingInTheStudyOrg(statisticDTO, userIds, postionIds);
                        freightCultivate.setNumberOfPeopleParticipatingInTheStudy(numberOfPeopleParticipatingInTheStudy.size());
                        freightCultivate.setParticipantsInTheStudy(numberOfPeopleParticipatingInTheStudy);
                        // 学习总时长（h）
                        Integer totalStudyTime = ftbCultivatePositionStatisticesMapper.totalStudyTime(statisticDTO, userIds, postionIds);
                        freightCultivate.setTotalStudyTime(CultivatePerUtils.computeDivision(new BigDecimal(totalStudyTime)));
                        // 人均学习时长（h）
                        freightCultivate.setAverageStudyTimePerPerson(computeDivision(freightCultivate.getTotalStudyTime(), freightCultivate.getNumberOfPeopleParticipatingInTheStudy()));
                        freightCultivate.setTotalNumberOfCourses(totalNumberOfCourses);
                        // 已学课程数
                        Integer numberOfCoursesTaken = ftbCultivatePositionStatisticesMapper.numberOfCoursesTakens(statisticDTO, userIds, postionIds);
                        freightCultivate.setNumberOfCoursesTaken(numberOfCoursesTaken);
                    }
                    return freightCultivate;
                }).collect(Collectors.toList());
            }, threadPoolTaskExecutor));
        }
        // 使用CompletableFuture.allOf等待所有任务完成
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        // 等待所有任务完成
        allTasks.join();
        // 收集所有任务的结果
        List<FtbCultivatePositionOrgStatisticesVO> results = futures.stream()
                .map(CompletableFuture::join)
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        // 线程等待
        return CultivatePage.paginate(results, page);
    }

    @Override
    public PageListVO<FtbCultivatePositionPersonStatisticesVO> personListStatistics(FtbCultivatePositionPersonStatisticesDTO ftbCultivatePositionPersonStatisticesDTO) {
        Page<FtbCultivatePositionPersonStatisticesVO> page = ftbCultivatePositionPersonStatisticesDTO.coverCultivatePage();

        // 关键词搜索
        if (StringUtils.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getKeyWords())) {
            boolean keywordSearch = false;
            // 员工姓名和员工ID
            List<Map<String, String>> userIds = ftbCultivatePositionStatisticesMapper.fuzzySearchForRosterKeywords(ftbCultivatePositionPersonStatisticesDTO.getKeyWords());
            if (CollUtil.isNotEmpty(userIds)) {

                ftbCultivatePositionPersonStatisticesDTO.getUserIds().addAll(userIds.stream()
                        .map(a -> a.get("userId")).collect(Collectors.toList()));
                keywordSearch = true;
            }
            // 组织ID
            List<String> organizationalIdCollection = cultivatePerUtils.convertOrganizationalIdCollection(ftbCultivatePositionPersonStatisticesDTO.getKeyWords());
            if (CollUtil.isNotEmpty(organizationalIdCollection)) {
                List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(organizationalIdCollection, null);
                if (CollUtil.isNotEmpty(userListForOrgIds)) {
                    List<String> userIdSe = userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList());
                    ftbCultivatePositionPersonStatisticesDTO.getUserIds().addAll(userIdSe);
                    keywordSearch = true;
                }
            }
            // 岗位名称
//            List<UserEntity> userByPositionName = userApi.getUserByPositionName(ftbCultivatePositionPersonStatisticesDTO.getKeyWords());
            List<UserRelationBaseVO> userByPositionName = userApiV2Util.getUserListForPositionName(ftbCultivatePositionPersonStatisticesDTO.getKeyWords(), null);
            if (CollUtil.isNotEmpty(userByPositionName)) {
                List<String> datas = userByPositionName.stream().map(UserRelationBaseVO::getUserId).collect(Collectors.toList());
                ftbCultivatePositionPersonStatisticesDTO.getUserIds().addAll(datas);
                keywordSearch = true;
            }
            if (!keywordSearch) {//说明keyword搜索条件无数据
                return CultivatePage.coverPageList(page);
            }
        }
        // 选择组织搜索
        if (CollUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getOrgId())) {
            List<UserPageListVO> userListForOrgIds = userApiV2Util.getUserListForOrgIds(ftbCultivatePositionPersonStatisticesDTO.getOrgId(), null);
            if (CollUtil.isNotEmpty(userListForOrgIds)) {
                List<String> userIdSe = userListForOrgIds.stream().map(UserPageListVO::getId).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getUserIds())) {
                    ftbCultivatePositionPersonStatisticesDTO.getUserIds().retainAll(userIdSe);
                } else {
                    ftbCultivatePositionPersonStatisticesDTO.getUserIds().addAll(userIdSe);
                }
            } else {
                return CultivatePage.coverPageList(page);
            }
        }
        if (CollUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getSelectPeoples())) {
            if (CollUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getUserIds())) {
                ftbCultivatePositionPersonStatisticesDTO.getUserIds().retainAll(ftbCultivatePositionPersonStatisticesDTO.getSelectPeoples());
            } else {
                ftbCultivatePositionPersonStatisticesDTO.getUserIds().addAll(ftbCultivatePositionPersonStatisticesDTO.getSelectPeoples());
            }
        }

        List<CultivatePositionCourseVo> courseIdList = ftbCultivatePositionStatisticesMapper.queryCourseIds();
        if (CollectionUtil.isEmpty(courseIdList)) {
            return CultivatePage.coverPageList(page);
        }
        List<String> courseIds = courseIdList.stream().map(CultivatePositionCourseVo::getCourseId).collect(Collectors.toList());
//        courseIdList 按照岗位分组
        Map<String, List<CultivatePositionCourseVo>> postCourseMap = new HashMap<>();
        for (CultivatePositionCourseVo cultivatePositionCourseVo : courseIdList) {
            if (StrUtil.isEmpty(cultivatePositionCourseVo.getGradeId())) {
                postCourseMap.computeIfAbsent(cultivatePositionCourseVo.getPostId(), k -> new ArrayList<>()).add(cultivatePositionCourseVo);
            } else {
                postCourseMap.computeIfAbsent(cultivatePositionCourseVo.getPostId() + "_" + cultivatePositionCourseVo.getGradeId(), k -> new ArrayList<>()).add(cultivatePositionCourseVo);
            }
        }
        ftbCultivatePositionPersonStatisticesDTO.setInnerCourseIds(courseIds);
        InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
        if (innerPowerUserVO.getCode() == 1) {
            if (CollUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getUserIds())) {
                List<String> intersection = UserApiV2Util.getIntersection(innerPowerUserVO.getUserIds(), ftbCultivatePositionPersonStatisticesDTO.getUserIds());
                if (CollUtil.isNotEmpty(intersection)) {
                    ftbCultivatePositionPersonStatisticesDTO.setUserIds(intersection);
                } else {
                    return CultivatePage.coverPageList(page);
                }
            } else {
                ftbCultivatePositionPersonStatisticesDTO.setUserIds(innerPowerUserVO.getUserIds());
            }
        } else if (innerPowerUserVO.getCode() == 2) {
            return CultivatePage.coverPageList(page);
        }

        page = ftbCultivatePositionStatisticesMapper.personListStatistics(page, ftbCultivatePositionPersonStatisticesDTO);
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            List<String> userIds = page.getRecords().stream().map(FtbCultivatePositionPersonStatisticesVO::getUserId).collect(Collectors.toList());
            List<FtbCultivatePositionPersonStatisticesVO> records = page.getRecords();
            Map<String, UserBoundVO> userToOrgMap = userApiV2Util.getUserPrimaryBoundBatchReturnMap(userIds, null);
            Map<String, List<CultivateUserPositionVo>> promotionMap = batchQueryPositionToLearnPositionIdsV2(userToOrgMap); //用户-到岗位列表
            List<V2UserCourseStudyVo> userCourseStudyVos = batchQueryAllCourseStudyV2(userIds);
            //按照用户id分组
            Map<String, List<V2UserCourseStudyVo>> userCourseStudyMap = userCourseStudyVos.stream().collect(Collectors.groupingBy(V2UserCourseStudyVo::getUserId));

            Map<String, List<String>> leaderMap = batchQueryUserInfoByLeaderIdsV2(userIds);
            List<List<FtbCultivatePositionPersonStatisticesVO>> allList = batchRecords(records, 100);
            UserInfo userInfo = UserProvider.getUser();
            String tenantId = userInfo.getTenantId();
            String token = userInfo.getToken();
            Map<String, String> headers = ImmutableMap.of(Constants.AUTHORIZATION.toLowerCase(), token);
            //多线程调用 convertToFtbRosterImportTemplateBatch 这个方法
            List<CompletableFuture<List<String>>> futures = allList.stream()
                    .map(item -> CompletableFuture.supplyAsync(() -> {
                        try {
                            FeignHolder.set(headers);
                            batchFillStatisticsV2(tenantId, postCourseMap, item, userToOrgMap, promotionMap, userCourseStudyMap, leaderMap);
                            return List.of("成功");
                        } finally {
                            FeignHolder.clear();
                        }
                    }, threadPoolTaskExecutor))
                    .collect(Collectors.toList());
            //搜集结果并返回
            List<String> collect = futures.stream()
                    .map(CompletableFuture::join)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());
            log.error("成功");
        }
        return CultivatePage.coverPageList(page);
    }

    private List<V2UserCourseStudyVo> batchQueryAllCourseStudyV2(List<String> userIds) {
        List<V2UserCourseStudyVo> v2UserCourseStudyVos = ftbCultivatePositionStatisticesMapper.batchQueryAllCourseStudyV2(userIds);
        if (CollUtil.isEmpty(v2UserCourseStudyVos)) {
            return new ArrayList<>();
        }
        return v2UserCourseStudyVos;
    }

    private List<UserCourseStudyVo> batchQueryAllCourseStudy(List<String> userIds) {
        List<UserCourseStudyVo> v2UserCourseStudyVos = ftbCultivatePositionStatisticesMapper.batchQueryAllCourseStudy(userIds);
        if (CollUtil.isEmpty(v2UserCourseStudyVos)) {
            return new ArrayList<>();
        }
        return v2UserCourseStudyVos;
    }

    public List<List<FtbCultivatePositionPersonStatisticesVO>> batchRecords(List<FtbCultivatePositionPersonStatisticesVO> records, int batchSize) {
        List<List<FtbCultivatePositionPersonStatisticesVO>> batches = new ArrayList<>();
        int totalBatches = (int) Math.ceil((double) records.size() / batchSize);

        for (int i = 0; i < totalBatches; i++) {
            int start = i * batchSize;
            int end = Math.min(start + batchSize, records.size());
            List<FtbCultivatePositionPersonStatisticesVO> batch = records.subList(start, end);
            batches.add(batch);
        }

        return batches;
    }


    private void batchFillStatisticsV2(String tenantCode,
                                       Map<String, List<CultivatePositionCourseVo>> postCourseMap,
                                       List<FtbCultivatePositionPersonStatisticesVO> records,
                                       Map<String, UserBoundVO> userToOrgMap,
                                       Map<String, List<CultivateUserPositionVo>> postionToLearnPostionIdsMap,
                                       Map<String, List<V2UserCourseStudyVo>> userCourseStudyMap,
                                       Map<String, List<String>> leaderMap) {
        try {
            TenantDataSourceUtil.switchTenant(tenantCode);
        } catch (LoginException e) {
            throw new RuntimeException(e);
        }
        records.forEach(item -> {
            // 所属组织
            UserBoundVO userBoundVO = userToOrgMap.get(item.getUserId());
            int localPositionStudyCourses = 0;//已经完成学习的本岗课程数量
            int localPositionStudyCoursesNeed = 0;//已经完成学习的本岗课程数量(必修)
            //本岗
            List<CultivatePositionCourseVo> localPostionCourseVos = new ArrayList<>();//本岗所有
            List<CultivatePositionCourseVo> localPostionCourseVosNees = new ArrayList<>();//本岗所有(必须)
            // 组织ID
            if (userBoundVO != null) {
                item.setOrganization(List.of(userBoundVO.getOrganizeName()));
                if (StringUtils.isNotEmpty(userBoundVO.getOrganizeEnCode())) {
                    item.setOrganizationCustomId(List.of(userBoundVO.getOrganizeEnCode()));
                }
                item.setEmployeeName(userBoundVO.getUserName());
                item.setEmployeeCustomId(userBoundVO.getSystemWorkerId());
                List<FtbCultivatePositionPersonStatisticesVO.PositionInfo> positionInfos = new ArrayList<>();
                if (StrUtil.isNotEmpty(userBoundVO.getPositionId())) {
                    FtbCultivatePositionPersonStatisticesVO.PositionInfo positionInfo = new FtbCultivatePositionPersonStatisticesVO.PositionInfo();
                    positionInfo.setPositionName(userBoundVO.getPositionName());
                    positionInfo.setPositionGradesName(userBoundVO.getGradeName());
                    positionInfos.add(positionInfo);
                }
                item.setThisPosition(positionInfos);
                // 学习-岗位
                List<CultivateUserPositionVo> learnPostionIds = postionToLearnPostionIdsMap.getOrDefault(userBoundVO.getId(),new ArrayList<>());
                List<V2UserCourseStudyVo> v2UserCourseStudyVos = userCourseStudyMap.getOrDefault(item.getUserId(),new ArrayList<>());
                Map<String, V2UserCourseStudyVo> v2UserCourseStudyMap = v2UserCourseStudyVos.stream()
                        .collect(Collectors.toMap(V2UserCourseStudyVo::getCourseId, a -> a));
                if (CollUtil.isNotEmpty(learnPostionIds)) {
                    Integer numberOfStudyCourses = 0;
                    for (CultivateUserPositionVo tempVo : learnPostionIds) {
                        String learnPostionId = tempVo.getPostId();
                        if (StrUtil.isNotEmpty(tempVo.getGradeId())) {
                            learnPostionId = learnPostionId + "_" + tempVo.getGradeId();
                        }
                        List<CultivatePositionCourseVo> cultivatePositionCourseVos = postCourseMap.get(learnPostionId);
                        if (CollUtil.isNotEmpty(cultivatePositionCourseVos)) {
                            numberOfStudyCourses += cultivatePositionCourseVos.size();
                        }
                    }
                    // 学习地图课程总数
                    item.setTotalNumberOfLearningMapCourses(numberOfStudyCourses);
                }
                String localPostionKey = userBoundVO.getPositionId();
                if (postCourseMap.containsKey(localPostionKey)) {
                    localPostionCourseVos = postCourseMap.get(localPostionKey);
                } else {
                    if (StrUtil.isNotEmpty(userBoundVO.getGradeId())) {
                        localPostionKey = localPostionKey + "_" + userBoundVO.getGradeId();
                    }
                    localPostionCourseVos = postCourseMap.get(localPostionKey);
                }
                if (CollUtil.isNotEmpty(localPostionCourseVos)) {
                    for (CultivatePositionCourseVo localPostionCourseVo : localPostionCourseVos) {
                        if (localPostionCourseVo.getCompulsory().equals(0)) {
                            localPostionCourseVosNees.add(localPostionCourseVo);
                        }
                        V2UserCourseStudyVo v2UserCourseStudyVo = v2UserCourseStudyMap.get(localPostionCourseVo.getCourseId());
                        if (v2UserCourseStudyVo != null) {
                            if (!v2UserCourseStudyVo.getState().equals(0)) {
                                localPositionStudyCourses++;
                                if (localPostionCourseVo.getCompulsory().equals(0) && v2UserCourseStudyVo.getState() == 1) {
                                    localPositionStudyCoursesNeed++;
                                }
                            }
                        }
                    }
                }
                item.setNumberOfStudyCourses(localPositionStudyCourses);
            }
            // 学习时长(h)
            item.setStudyDuration(CultivatePerUtils.computeDivision(item.getStudyDuration()));

            item.setCourseCompletionRate(computeDivision(localPositionStudyCoursesNeed, localPostionCourseVosNees.size()));
            // 下属人数
            List<String> subordinateUserId = leaderMap.get(item.getUserId());
            // 下属参与学习人数
            if (CollectionUtils.isNotEmpty(subordinateUserId)) {
                item.setNumberOfSubordinates(subordinateUserId.size());
                List<String> tempCourseIds = new ArrayList<>();
                if (CollUtil.isNotEmpty(localPostionCourseVos)) {
                    tempCourseIds.addAll(localPostionCourseVos.stream().map(CultivatePositionCourseVo::getCourseId).collect(Collectors.toList()));
                } else {
                    tempCourseIds.add("-1");
                }
                V2StudyCountVo v2StudyCountVo = ftbCultivatePositionStatisticesMapper.numberOfPeopleParticipatingInTheStudy(subordinateUserId, tempCourseIds);
//                Integer numberOfPeopleParticipatingInTheStudy = ftbCultivatePositionStatisticesMapper.numberOfPeopleParticipatingInTheStudy1(subordinateUserId, innerCourseIds);
                item.setNumberOfSubordinatesParticipatingInLearning(v2StudyCountVo.getUserNumber());
                // 下属人均学习时长
//                Integer averageStudyHoursPerSubordinate = ftbCultivatePositionStatisticesMapper.averageStudyHoursPerSubordinate1(subordinateUserId, innerCourseIds);
                item.setAverageStudyHoursPerSubordinate(computeDivision(CultivatePerUtils.computeDivision(new BigDecimal(v2StudyCountVo.getTotalSeconds()))
                        , subordinateUserId.size()));
            } else {
                item.setNumberOfSubordinatesParticipatingInLearning(0);
                item.setAverageStudyHoursPerSubordinate(BigDecimal.ZERO);
            }

        });
    }

    private Map<String, PositionVO> batchQueryPosition(Map<String, List<UserBoundVO>> userToOrgMap) {
        List<String> positionList = new ArrayList<>();
        for (Map.Entry<String, List<UserBoundVO>> entry : userToOrgMap.entrySet()) {
            UserBoundVO workerGroupDataDto = entry.getValue().get(0);
            if (StringUtils.isNotEmpty(workerGroupDataDto.getPositionId())) {
                positionList.add(workerGroupDataDto.getPositionId());
            }
        }
        if (CollectionUtil.isEmpty(positionList)) {
            return new HashMap<>();
        }
        return userApiV2Util.listPositionDetailInfoByIdsReturnMap(UserApiV2Util.uniqueStringList(positionList), null);
    }

    private Map<String, PositionVO> batchQueryPositionV2(Map<String, UserBoundVO> userToOrgMap) {
        List<String> positionList = new ArrayList<>();
        for (Map.Entry<String, UserBoundVO> entry : userToOrgMap.entrySet()) {
            if (StringUtils.isNotEmpty(entry.getValue().getPositionId())) {
                positionList.add(entry.getValue().getPositionId());
            }
        }
        if (CollectionUtil.isEmpty(positionList)) {
            return new HashMap<>();
        }
        return userApiV2Util.listPositionDetailInfoByIdsReturnMap(UserApiV2Util.uniqueStringList(positionList), null);
    }


    private Map<String, List<String>> batctQueryUserInfoByLeaderIds(List<String> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return new HashMap<>();
        }
        Map<String, List<String>> map = new HashMap<>();
        for (String userId : userIds) {
            List<UserPageListVO> listVOS = userApiV2Util.listUnderlingTargetUser(userId, null);
            if (CollUtil.isNotEmpty(listVOS)) {
                map.put(userId, listVOS.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
            } else {
                map.put(userId, new ArrayList<>());
            }
        }
        return map;
    }

    private Map<String, List<String>> batchQueryUserInfoByLeaderIdsV2(List<String> userIds) {
        Map<String, List<String>> map = new HashMap<>();
        if (CollUtil.isEmpty(userIds)) {
            return map;
        }
        List<PersonForLeaderVo> list = ftbCultivatePositionStatisticesMapper.queryAllNextUser(userIds);
        if (CollUtil.isEmpty(list)) {
            return map;
        }
        for (PersonForLeaderVo personForLeaderVo : list) {
            if (map.containsKey(personForLeaderVo.getLeaderId())) {
                map.get(personForLeaderVo.getLeaderId()).add(personForLeaderVo.getUserId());
            } else {
                List<String> tempList = new ArrayList<>();
                tempList.add(personForLeaderVo.getUserId());
                map.put(personForLeaderVo.getLeaderId(), tempList);
            }
        }
        return map;
    }

    private Map<String, PersonStatisticesDto> batchQueryCount(List<String> userIds, int type, List<String> courseIds) {
        Map<String, PersonStatisticesDto> ret = new HashMap<>();
        if (CollectionUtil.isEmpty(userIds)) {
            return ret;
        }
        List<PersonStatisticesDto> list = ftbCultivatePositionStatisticesMapper.batchNumberOfStudyCourses2(userIds, type, courseIds);
        if (CollectionUtil.isEmpty(list)) {
            return ret;
        }
        for (PersonStatisticesDto personStatisticesDto : list) {
            ret.put(personStatisticesDto.getUserId(), personStatisticesDto);
        }
        return ret;
    }

    private Map<String, List<String>> batchQueryPositionToLearnPositionIds(Map<String, List<UserBoundVO>> userToOrgMap) {
        // 初始化返回结果
        Map<String, List<String>> ret = new HashMap<>();

        // 空值校验
        if (CollectionUtil.isEmpty(userToOrgMap)) {
            return ret;
        }

        // 提取所有用户ID
        List<String> userIds = new ArrayList<>(userToOrgMap.keySet());

        // 查询用户的晋升岗位信息
        List<CultivateUserPositionVo> promotionList = ftbCultivatePromotionNewService.queryPromotionPosition(userIds);

        // 构建用户ID到晋升岗位的映射
        Map<String, List<CultivateUserPositionVo>> promotionMap = promotionList.stream()
                .collect(Collectors.groupingBy(CultivateUserPositionVo::getUserId));

        // 遍历用户，构建学习路径
        userToOrgMap.forEach((userId, userBoundList) -> {
            // 获取晋升岗位ID列表
            List<String> promotionPostIds = Optional.ofNullable(promotionMap.get(userId))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(CultivateUserPositionVo::getPostId)
                    .collect(Collectors.toList());

            // 获取当前岗位ID（取第一个岗位）
            String currentPositionId = Optional.ofNullable(userBoundList)
                    .filter(list -> !list.isEmpty())
                    .map(list -> list.get(0).getPositionId())
                    .filter(StringUtils::isNotEmpty)
                    .orElse(null);

            // 合并晋升岗位和当前岗位ID
            List<String> learnPositionIds = new ArrayList<>(promotionPostIds);
            if (currentPositionId != null) {
                learnPositionIds.add(currentPositionId);
            }

            // 存入结果
            ret.put(userId, learnPositionIds);
        });

        return ret;
    }


    private Map<String, List<CultivateUserPositionVo>> batchQueryPositionToLearnPositionIdsV2(Map<String, UserBoundVO> userToOrgMap) {
        // 初始化返回结果
        Map<String, List<CultivateUserPositionVo>> ret = new HashMap<>();

        // 空值校验
        if (CollectionUtil.isEmpty(userToOrgMap)) {
            return ret;
        }

        // 提取所有用户ID
        List<String> userIds = new ArrayList<>(userToOrgMap.keySet());

        // 查询用户的晋升岗位信息
        List<CultivateUserPositionVo> promotionList = ftbCultivatePromotionNewService.queryPromotionPosition(userIds);
        if (CollUtil.isNotEmpty(promotionList)) {
            // 构建用户ID到晋升岗位的映射
            ret = promotionList.stream()
                    .collect(Collectors.groupingBy(CultivateUserPositionVo::getUserId));
        }
        return ret;
    }

    private Map<String, FtbPersonnelsStaffRoster> convertStaffRosterMap(List<FtbPersonnelsStaffRoster> ftbPersonnelsStaffRosters) {
        Map<String, FtbPersonnelsStaffRoster> userToRosterMap = new HashMap<>();
        if (CollectionUtil.isNotEmpty(ftbPersonnelsStaffRosters)) {
            for (FtbPersonnelsStaffRoster ftbPersonnelsStaffRoster : ftbPersonnelsStaffRosters) {
                userToRosterMap.put(ftbPersonnelsStaffRoster.getUserId(), ftbPersonnelsStaffRoster);
            }
        }
        return userToRosterMap;
    }

    private Map<String, List<WorkerGroupDataDto>> BatchQueryUserOrgPositionRank(List<FtbCultivatePositionPersonStatisticesVO> records) {
        Map<String, List<WorkerGroupDataDto>> retMap = new HashMap<>();
        if (CollectionUtil.isEmpty(records)) {
            return retMap;
        }
        List<String> userIdList = new ArrayList<>();
        for (FtbCultivatePositionPersonStatisticesVO record : records) {
            userIdList.add(record.getUserId());
        }

//        List<UserBoundMoreInfoVO> selectList = userApi.getUserBoundMoreInfosByUserIds(userIdList);
        Map<String, List<UserBoundVO>> map = userApiV2Util.getUserPrimaryBoundBatchCompatible(userIdList, null);
        if (CollectionUtil.isEmpty(map)) {
            return new HashMap<>();
        }

        for (Map.Entry<String, List<UserBoundVO>> entry : map.entrySet()) {
            String userId = entry.getKey(); // 用户ID
            List<UserBoundVO> list = entry.getValue(); // 获取值列表
            List<WorkerGroupDataDto> workerGroupDataDtoList = new ArrayList<>();
            for (UserBoundVO vo : list) {
                WorkerGroupDataDto dto = new WorkerGroupDataDto();
                dto.setAffiliatedOrg(vo.getOrganizeId());
                dto.setAffiliatedOrgName(vo.getOrganizeName());
                dto.setAffiliatedPosition(vo.getPositionId());
                dto.setAffiliatedPositionName(vo.getPositionName());
                dto.setAffiliatedRank(vo.getGradeId());
                dto.setAffiliatedRankName(vo.getGradeName());
                dto.setOrgEncode(vo.getOrganizeEnCode());
                dto.setPositionEncode(vo.getPositionEnCode());
                workerGroupDataDtoList.add(dto);
            }
            retMap.put(userId, workerGroupDataDtoList);
        }
        return retMap;
    }

    /**
     * 返回一个空的分页结果列表
     *
     * @param statisticDTO 统计查询参数DTO
     * @return 空的分页结果列表
     */
    private PageListVO<FtbCultivatePersonStatisticesVO> returnEmptyList(FtbCultivatePersonStatisticesDTO statisticDTO) {
        PageListVO<FtbCultivatePersonStatisticesVO> pageInfo = new PageListVO<>();
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(statisticDTO.getCurrentPage());
        pagination.setPageSize(statisticDTO.getPageSize());
        pagination.setTotal(0);
        pageInfo.setList(new ArrayList<>());
        pageInfo.setPagination(pagination);
        return pageInfo;
    }

    @Override
    public PageListVO<FtbCultivatePersonStatisticesVO> positionListStatistics(FtbCultivatePersonStatisticesDTO ftbCultivatePositionPersonStatisticesDTO) {
        String tenantId = UserProvider.getUser().getTenantId();
        Page<FtbCultivatePersonStatisticesVO> page = ftbCultivatePositionPersonStatisticesDTO.coverCultivatePage();
        List<String> powerPositionList = new ArrayList<>();
        InnerPowerUserVO innerPowerUserVO = userApiV2Util.getLoginManagerUserIdsForEncode();
        if (innerPowerUserVO.getCode().equals(1)) {
            List<UserBoundVO> userPrimaryBoundBatchReturnList = userApiV2Util.getUserPrimaryBoundBatchReturnList(innerPowerUserVO.getUserIds(), tenantId);
            if (CollUtil.isEmpty(userPrimaryBoundBatchReturnList)) {
                page.setRecords(new ArrayList<>());
                return CultivatePage.coverPageList(page);
            }
            powerPositionList = UserApiV2Util.uniqueStringList(userPrimaryBoundBatchReturnList.stream().map(UserBoundVO::getPositionId).collect(Collectors.toList()));
            if (StrUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getPostId())) {
                List<String> queryPositoinList = List.of(ftbCultivatePositionPersonStatisticesDTO.getPostId().split(","));
                List<String> intersection = UserApiV2Util.getIntersection(powerPositionList, queryPositoinList);

                if (CollUtil.isEmpty(intersection)) {
                    return returnEmptyList(ftbCultivatePositionPersonStatisticesDTO);
                } else {
                    powerPositionList = intersection;
                }
            }

        } else if (innerPowerUserVO.getCode().equals(2)) {
            // 线程等待
            return returnEmptyList(ftbCultivatePositionPersonStatisticesDTO);
        } else {
            if (StrUtil.isNotEmpty(ftbCultivatePositionPersonStatisticesDTO.getPostId())) {
                powerPositionList = List.of(ftbCultivatePositionPersonStatisticesDTO.getPostId().split(","));
            }
        }
        ftbCultivatePositionPersonStatisticesDTO.setPowerPositionList(powerPositionList);

        page = ftbCultivatePositionStatisticesMapper.positionListStatistics(page, ftbCultivatePositionPersonStatisticesDTO);
        if (CollectionUtil.isEmpty(page.getRecords())) return CultivatePage.coverPageList(page);
        List<String> postionIds = page.getRecords().stream()
                .map(FtbCultivatePersonStatisticesVO::getPositionId).collect(Collectors.toList());
        List<String> postionLearnIds = page.getRecords().stream()
                .map(FtbCultivatePersonStatisticesVO::getPostLearnId).collect(Collectors.toList());
        // 岗位信息
//        List<PositionInfoDimensionVO> morePositionInfoDimensionByIds = positionApi.getMorePositionInfoDimensionByIds(postionIds);
        List<PositionVO> morePositionInfoDimensionByIds = userApiV2Util.listPositionDetailInfoByIds(postionIds, tenantId);
        List<UserBoundVO> userListForPositions = userApiV2Util.getUserListForPositions(postionIds, tenantId);
        Map<String, List<UserBoundVO>> userNumMaptemp = new HashMap<>(); //岗位->用户列表
        if (CollUtil.isNotEmpty(userListForPositions)) {
            userNumMaptemp = userListForPositions.stream().collect(Collectors.groupingBy(UserBoundVO::getPositionId));
        }
        final Map<String, List<UserBoundVO>> userNumMap = userNumMaptemp;
        Map<String, PositionVO> stringPositionInfoDimensionVOMap = new HashMap<>();

        if (CollUtil.isNotEmpty(morePositionInfoDimensionByIds)) {
            for (PositionVO morePositionInfoDimensionById : morePositionInfoDimensionByIds) {
                stringPositionInfoDimensionVOMap.put(morePositionInfoDimensionById.getId(), morePositionInfoDimensionById);
            }
        }
        // 岗位考试合格率
        List<FtbCultivatePersonStatisticesVO.PassedTheExam> passedTheExams = ftbCultivatePositionStatisticesMapper.checkJobQualificationRate(postionIds);
        Map<String, BigDecimal> passedTheExamsMap = new HashMap<>();
        if (CollUtil.isNotEmpty(passedTheExams)) {
            for (FtbCultivatePersonStatisticesVO.PassedTheExam passedTheExam : passedTheExams) {
                passedTheExamsMap.put(passedTheExam.getPositionId(), passedTheExam.getAverageStudyHoursPerSubordinate());
            }
        }
        // 已学习课程数
        List<FtbCultivatePersonStatisticesVO.NumberOfCoursesTaken> numberOfCoursesTakens = ftbCultivatePositionStatisticesMapper.numberOfCoursesTaken(postionIds);
        Map<String, Integer> numberOfCoursesTakensMap = numberOfCoursesTakens.stream()
                .collect(Collectors.toMap(FtbCultivatePersonStatisticesVO.NumberOfCoursesTaken::getPositionId,
                        FtbCultivatePersonStatisticesVO.NumberOfCoursesTaken::getNumberOfCoursesTaken, (k1, k2) -> k1));
        // 岗位学习课程总数
        List<FtbCultivatePersonStatisticesVO.TotalNumberOfOnTheJobLearningCourses> totalNumberOfOnTheJobLearningCoursess = ftbCultivatePositionStatisticesMapper
                .totalNumberOfOnTheJobLearningCourses(postionLearnIds);
        Map<String, Integer> totalNumberOfOnTheJobLearningCoursesMap = totalNumberOfOnTheJobLearningCoursess.stream()
                .collect(Collectors.toMap(FtbCultivatePersonStatisticesVO.TotalNumberOfOnTheJobLearningCourses::getPositionId,
                        FtbCultivatePersonStatisticesVO.TotalNumberOfOnTheJobLearningCourses::getTotalNumberOfOnTheJobLearningCourses, (k1, k2) -> k1));
        List<FtbCultivatePersonStatisticesVO> records = page.getRecords();
        List<List<FtbCultivatePersonStatisticesVO>> partition = new ArrayList<>();
        if (records.size() > 2000) {
            partition = Lists.partition(records, 10);
        } else if (500 < records.size() && records.size() < 1000) {
            partition = Lists.partition(records, 5);
        } else {
            partition = Lists.partition(records, 1);
        }
        List<CompletableFuture<List<FtbCultivatePersonStatisticesVO>>> futures = new ArrayList<>();
        for (List<FtbCultivatePersonStatisticesVO> personStatisticesVOList : partition) {
            futures.add(CompletableFuture.supplyAsync(() -> {
                return personStatisticesVOList.parallelStream().map(vo -> {
                    FtbCultivatePersonStatisticesVO item = new FtbCultivatePersonStatisticesVO();
                    // 所属组织相关
                    item.setPositionId(vo.getPositionId());
                    String positionId = vo.getPositionId();
                    String postLearnId = vo.getPostLearnId();
                    PositionVO positionInfoDimensionVO = stringPositionInfoDimensionVOMap.get(positionId);
                    log.info("获取岗位维度远程调用:{}", positionInfoDimensionVO);
                    item.setPositionTitle(positionInfoDimensionVO.getFullName());
                    item.setPositionCustomId(positionInfoDimensionVO.getEnCode());
                    if (CollUtil.isNotEmpty(positionInfoDimensionVO.getOrganizes())) {
                        List<OrganizeFullBasicVO> organizes = positionInfoDimensionVO.getOrganizes();
                        List<String> orgEncode = new ArrayList<>();
                        List<String> orgFullName = new ArrayList<>();
                        List<String> orgIds = new ArrayList<>();
                        for (OrganizeFullBasicVO organize : organizes) {
                            orgIds.add(organize.getId());
                            orgEncode.add(organize.getEnCode());
                            orgFullName.add(organize.getName());
                        }
                        item.setOrganizationCustomId(orgEncode);
                        item.setOrganization(orgFullName);
                        item.setOrgIds(orgIds);
                    }

                    // 获取该岗位下所有人
                    List<String> userIdsByGradesId = new ArrayList<>();
                    List<UserBoundVO> positionListUserVO = userNumMap.get(positionId);
                    if (CollUtil.isNotEmpty(positionListUserVO)) {
                        userIdsByGradesId = positionListUserVO.stream().map(UserBoundVO::getId).collect(Collectors.toList());
                    }
                    item.setNumberOfPositions(userIdsByGradesId.size());
                    try {
                        TenantDataSourceUtil.switchTenant(tenantId);
                        if (CollectionUtils.isNotEmpty(userIdsByGradesId)) {
                            // 岗位学习人数
                            List<String> numberOfPeopleStudyingOnTheJobs = ftbCultivatePositionStatisticesMapper.numberOfPeopleStudyingOnTheJob(userIdsByGradesId);
                            item.setParticipantsInTheStudy(numberOfPeopleStudyingOnTheJobs);
                            Integer numberOfPeopleStudyingOnTheJob = numberOfPeopleStudyingOnTheJobs.size();
                            item.setNumberOfPeopleStudyingOnTheJob(numberOfPeopleStudyingOnTheJob);
                            // 学习时长
                            Long studyDuration = ftbCultivatePositionStatisticesMapper.studyDuration(userIdsByGradesId);
                            item.setStudyDuration(CultivatePerUtils.computeDivision(new BigDecimal(studyDuration)));
                            // 人均学习时长
                            item.setAverageStudyTimePerPerson(computeDivision(item.getStudyDuration(), numberOfPeopleStudyingOnTheJob));
                        }
                        // 岗位学习课程总数

                        Integer totalNumberOfOnTheJobLearningCourses = totalNumberOfOnTheJobLearningCoursesMap.get(postLearnId);
                        item.setTotalNumberOfOnTheJobLearningCourses(totalNumberOfOnTheJobLearningCourses);
                        // 已学习课程数
                        Integer numberOfCoursesTaken = numberOfCoursesTakensMap.get(positionId);
                        item.setNumberOfCoursesTaken(numberOfCoursesTaken);
                        // 岗位学习完课率
                        item.setCourseCompletionRate(computeDivision(numberOfCoursesTaken, totalNumberOfOnTheJobLearningCourses));
                        // 岗位学习考试合格率
                        item.setAverageStudyHoursPerSubordinate(passedTheExamsMap.get(positionId));
                    } catch (LoginException e) {
                        throw new RuntimeException(e);
                    } finally {
                        DataSourceContextHolder.clearDatasourceType();
                    }
                    return item;
                }).collect(Collectors.toList());
            }, threadPoolTaskExecutor));
        }
        // 使用CompletableFuture.allOf等待所有任务完成
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
        // 等待所有任务完成
        allTasks.join();
        // 收集所有任务的结果
        List<FtbCultivatePersonStatisticesVO> results = futures.stream()
                .map(CompletableFuture::join)
                .flatMap(Collection::stream)
                .collect(Collectors.toList());
        // 线程等待
        page.setRecords(results);
        return CultivatePage.coverPageList(page);
    }

    @Override
    public List<OrganizeCourseDetails> organizeCourseDetails(String startDate, String endDate, String orgId) {
        List<PositionAndGradesVO> listByOrganizeIds = userApiV2Util.listPositionAndGradesByPositionNameForOrgIds(orgId, null);

        if (CollUtil.isEmpty(listByOrganizeIds)) {
            return new ArrayList<>();
        }
        String postionIds = listByOrganizeIds.stream().map(PositionAndGradesVO::getId).collect(Collectors.joining(","));
        List<UserPageListVO> allUser = userApiV2Util.getUserListForOrgIds(List.of(orgId), null);
        List<String> userIds = allUser.stream().map(UserPageListVO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        List<OrganizeCourseDetails> result = ftbCultivatePositionStatisticesMapper.organizeCourseDetails(startDate, endDate, postionIds, userIds);
        if (CollUtil.isEmpty(result)) {
            return new ArrayList<>();
        }
        List<String> allPositionIds = result.stream()
                .flatMap(v -> Arrays.stream(v.getPositionIds().split(",")))
                .collect(Collectors.toList());
        //查询岗位下的用户
        List<UserBoundVO> userBoundList = new ArrayList<>();
        if (CollUtil.isNotEmpty(allPositionIds)) {
            userBoundList = userApiV2Util.getUserListForPositions(allPositionIds, UserProvider.getUser().getTenantId());
        }
        userBoundList = userBoundList.stream()
                .filter(v -> orgId.equals(v.getOrganizeId()))
                .collect(Collectors.toList());
        Set<String> positionUserIds = userBoundList.stream()
                .map(UserBoundVO::getId)
                .collect(Collectors.toSet());
        Map<String, Set<String>> positionUserIdMap = userBoundList.stream()
                .filter(Objects::nonNull)
                .filter(v -> StrUtil.isNotBlank(v.getPositionId()))
                .filter(v -> StrUtil.isNotBlank(v.getId()))
                .collect(Collectors.groupingBy(
                        UserBoundVO::getPositionId,
                        Collectors.mapping(UserBoundVO::getId, Collectors.toSet())
                ));
        List<String> courseIds = result.stream()
                .map(OrganizeCourseDetails::getCourseId)
                .collect(Collectors.toList());
        // 已参与学习人数
        List<CourseStudyCountVO> numberOfPeopleParticipatingInTheStudy =
                CollUtil.isNotEmpty(positionUserIdMap.keySet()) ?
                        ftbCultivatePositionStatisticesMapper.numberOfPeopleParticipatingInTheFinishStudy(
                                courseIds, String.join(",", positionUserIdMap.keySet()), List.of(1, 2), positionUserIds
                        ) : new ArrayList<>();
        Map<String, Integer> finishStudyMap = numberOfPeopleParticipatingInTheStudy.stream()
                .collect(Collectors.toMap(CourseStudyCountVO::getCourseId, CourseStudyCountVO::getNum, (a, b) -> b));
        //根据岗位分组
        result.forEach(item -> {
            // 学习时长（h）
            item.setStudyDuration(CultivatePerUtils.computeDivision(item.getStudyDuration()));
            // 已参与学习人数
            Integer finishStudyMapOrDefault = finishStudyMap.getOrDefault(item.getCourseId(), 0);
            item.setNumberOfPeopleWhoHaveParticipatedInLearning(finishStudyMapOrDefault);
            // 应参与学习人数
            Set<String> shouldStudyUserIds = Optional.of(Arrays.asList(item.getPositionIds().split(",")))
                    .orElse(Collections.emptyList())
                    .stream()
                    .filter(StrUtil::isNotBlank)
                    .distinct()
                    .map(positionUserIdMap::get)
                    .filter(Objects::nonNull)
                    .flatMap(Collection::stream)
                    .collect(Collectors.toSet());
            item.setNumberOfPeopleParticipatingInTheStudy(shouldStudyUserIds.size());
            // 人均学习时长
            BigDecimal averageStudyTimePerPerson = computeDivision(item.getStudyDuration(), finishStudyMapOrDefault);
            item.setAverageStudyTimePerPerson(averageStudyTimePerPerson);
        });
        return result;
    }

    @Override
    public List<PersonalDimensionCourseDetails> personalDimensionCourseDetails(String startDate, String endDate, String userId) {
        List<PersonalDimensionCourseDetails> result = ftbCultivatePositionStatisticesMapper.personalDimensionCourseDetails(startDate, endDate, userId);
        if (CollUtil.isNotEmpty(result)) {
            // 只保留未完成的课程ID（state != 1）
            List<String> courseIds = result.stream()
                    .filter(item -> item.getState() == null || item.getState() != 1)
                    .map(PersonalDimensionCourseDetails::getCourseId)
                    .collect(Collectors.toList());
            Map<String, BigDecimal> learningStateMap = v2CultivateBatchQueryService.batchQueryUserCourseLearnProgress(userId, courseIds);
            //查询所有学习的章节 根据课程id
            result.forEach(item -> {
                // 学习时长（h）
                item.setStudyDuration(CultivatePerUtils.computeDivision(item.getStudyDuration()));
                // 课程学习进度（%）
                if (item.getState().equals(1)) {
                    // 已完成状态，进度为100%
                    item.setCourseLearningProgress(new BigDecimal("1"));
                } else {
                    BigDecimal bigDecimal = learningStateMap.get(item.getCourseId());
                    item.setCourseLearningProgress(bigDecimal != null ? bigDecimal : new BigDecimal("0"));
                }
            });
        }
        return result;
    }

    @Override
    public BigDecimal jobLearningProgress(String postId, String userId) {
        // 总数
        Integer a = ftbCultivatePositionStatisticesMapper.jobLearningProgress(postId, userId, null);
        // 已学课程数
        Integer b = ftbCultivatePositionStatisticesMapper.jobLearningProgress(postId, userId, 1);
        return computeDivision(b, a);
    }

    @Override
    public JobTitleStatistics jobTitleStatistics(String postId) {
        JobTitleStatistics result = new JobTitleStatistics();
        ExamCultivateForPositionVo examCultivateForPositionVo = ftbCultivateExamUserService.queryCultivateCountForPositionId(postId);
        // 参与岗位考试人数
        result.setNumberOfPeopleParticipatingInTheJobExam(examCultivateForPositionVo.getTotle());
        // 考试优秀人数
        result.setNumberOfPeopleWhoExcelledInTheExam(examCultivateForPositionVo.getExcellent());
        // 考试合格人数
        result.setNumberOfPeopleWhoPassedTheExam(examCultivateForPositionVo.getPass());
        // 考试不合格人数
        result.setNumberOfPeopleWhoFailedTheExam(examCultivateForPositionVo.getNoPass());
        // 完成学习人数
        // 获取该岗位下所有人
//        List<String> userIdsByGradesId = userApi.getUserIdsByGradesId("", postId, "");
        List<UserBoundVO> userIdsByGradesId = userApiV2Util.getUserListForPositions(List.of(postId), null);
        log.info("获取该岗位下所有人:{}", userIdsByGradesId);
        if (CollectionUtils.isNotEmpty(userIdsByGradesId)) {
            // 岗位学习人数
            List<String> userIds = userIdsByGradesId.stream().map(UserBoundVO::getId).collect(Collectors.toList());
            Integer numberOfPeopleStudyingOnTheJobs = ftbCultivatePositionStatisticesMapper.numberOfPeopleWhoCompletedTheStudy(userIds);
            result.setNumberOfPeopleWhoCompletedTheStudy(numberOfPeopleStudyingOnTheJobs);
        }

        return result;
    }


    public static BigDecimal computeDivision(Object a, Object b) {
        if (a == null || b == null || b.equals(0)) {
            return BigDecimal.ZERO;
        }
        // a/b 除数为0
        if (b instanceof Integer) {
            Integer b0 = (Integer) b;
            if (b0 == 0) {
                return BigDecimal.ZERO;
            }
        }
        if (b instanceof Long) {
            Long b0 = (Long) b;
            if (b0 == 0) {
                return BigDecimal.ZERO;
            }
        }
        BigDecimal a0 = new BigDecimal(String.valueOf(a));
        BigDecimal b0 = new BigDecimal(String.valueOf(b));
        return a0.divide(b0, 2, RoundingMode.HALF_UP);
    }

}
