package jnpf.personnels.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jnpf.base.ActionResult;
import jnpf.base.vo.PageListVO;
import jnpf.base.vo.PaginationVO;
import jnpf.model.cultivate.CultivatePage;
import jnpf.model.personnels.dto.analysis.FtbPersonnlesAnalysisDTO;
import jnpf.model.personnels.dto.staff.roster.WorkerGroupDataDto;
import jnpf.model.personnels.po.FtbPersonnelsRegularManagement;
import jnpf.model.personnels.po.FtbPersonnelsRuleConfig;
import jnpf.model.personnels.po.FtbPersonnelsStaffEmploymentApply;
import jnpf.model.personnels.po.FtbPersonnelsTurnoverManagement;
import jnpf.model.personnels.vo.analysis.*;
import jnpf.model.personnels.vo.regular.FtbPersonnelsRegularManagementVO;
import jnpf.model.personnels.vo.turnover.FtbPersonnelsTurnoverManagementVO;
import jnpf.model.personnels.vo.turnover.FtbPersonnelsTurnoverStatisticVO;
import jnpf.permission.V2PositionApi;
import jnpf.permission.V2UserApi;
import jnpf.permission.dto.v2.user.QueryPageUserDTO;
import jnpf.permission.dto.v2.user.QueryUserBatchDTO;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.vo.v2.user.UserBoundVO;
import jnpf.personnels.mapper.*;
import jnpf.personnels.service.FtbPersonnelsBrainDrainService;
import jnpf.personnels.service.FtbPersonnelsOverviewAnalysisService;
import jnpf.personnels.utils.CompanyAgeUtil;
import jnpf.personnels.utils.CovertDateUtils;
import jnpf.util.UserProvider;
import jnpf.util.excel.EasyExcelUtils;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: peng.hao
 * @create: 2025/4/11
 */
@Service
public class FtbPersonnelsBrainDrainServiceImpl implements FtbPersonnelsBrainDrainService {


    @Resource
    private FtbPersonnelsOverviewAnalysisMapper ftbPersonnelsOverviewAnalysisMapper;

    @Autowired
    V2UserApi v2UserApi;

    @Resource
    FtbPersonnelsRegularManagementMapper regularManagementMapper;

    @Resource
    FtbPersonnelsRuleConfigMapper ftbPersonnelsRuleConfigMapper;

    @Resource
    FtbPersonnelsStaffEmploymentApplyMapper applyMapper;

    @Resource
    FtbPersonnelsTurnoverManagementMapper turnoverManagementMapper;

    @Resource
    V2PositionApi v2PositionApi;

    public static final List<String> ON_THE_JOB_STATUS = List.of("302", "303", "304", "306");


    @Override
    public FtbPersonnlesBrainDrainVO getBrainDrainCorrectRateComparison(FtbPersonnlesAnalysisDTO dto) {
        FtbPersonnlesBrainDrainVO drainVO = new FtbPersonnlesBrainDrainVO();
        // 人事异动转正人数同比环比
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return drainVO;
        }
        // 截止当前月转正人数
        Long aLong = generalQueryOfTheNumberOfRegulars(dto.getStartTime(), dto.getEndTime(), userIdListByOrganizeIds, dto.getOrganizationId());
        drainVO.setData(BigDecimal.valueOf(aLong));
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearDateStart = DateUtil.offset(dto.getStartTime(), DateField.YEAR, -1).toJdkDate();
        Date yearOnYearDateEnd = DateUtil.offset(dto.getEndTime(), DateField.YEAR, -1).toJdkDate();
        Long yearOnYearDateValue = generalQueryOfTheNumberOfRegulars(yearOnYearDateStart, yearOnYearDateEnd, userIdListByOrganizeIds, dto.getOrganizationId());
        drainVO.setYearOnYear(FtbPersonnelsOverviewAnalysisService.computeDivisionSb(BigDecimal.valueOf(aLong).subtract(BigDecimal.valueOf(yearOnYearDateValue)), yearOnYearDateValue, 2));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chanelDateStart = DateUtil.offset(dto.getStartTime(), DateField.MONTH, -1).toJdkDate();
        Date chainDateEnd = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        Long chainDateValue = generalQueryOfTheNumberOfRegulars(chanelDateStart, chainDateEnd, userIdListByOrganizeIds, dto.getOrganizationId());
        drainVO.setChainValue(FtbPersonnelsOverviewAnalysisService.computeDivisionSb(BigDecimal.valueOf(aLong).subtract(BigDecimal.valueOf(chainDateValue)), chainDateValue, 2));
        return drainVO;
    }

    @Override
    public FtbPersonnlesBrainDrainVO getBrainDrainCorrectRateNewcomerRate(FtbPersonnlesAnalysisDTO dto) {
        FtbPersonnlesBrainDrainVO drainVO = new FtbPersonnlesBrainDrainVO();
        // 人事异动转正人数同比环比
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return drainVO;
        }
        LambdaQueryWrapper<FtbPersonnelsRuleConfig> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsRuleConfig::getEnableMark, 0);
        FtbPersonnelsRuleConfig ruleConfig = ftbPersonnelsRuleConfigMapper.selectOne(wrapper);
        Integer type = ruleConfig.getType();
        // 新人规则天数
        Integer timeRule = type == 1 ? ruleConfig.getTimeRule() : ruleConfig.getTimeRule() * 30;
        List<String> presenceOfPersonnel = getTheNumberOfPeopleInOffice(dto.getEndTime(), userIdListByOrganizeIds);
        int aLong = presenceOfPersonnel.size();
        // 查询新人人员数
        BigDecimal newcomerNum = ftbPersonnelsOverviewAnalysisMapper.queryTheNumberOfNewcomers(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()),
                userIdListByOrganizeIds, timeRule);
        // 本期数
        BigDecimal computeDivision = FtbPersonnelsOverviewAnalysisService.computeDivision(newcomerNum, aLong);
        drainVO.setData(computeDivision);
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearDateStart = DateUtil.offset(dto.getStartTime(), DateField.YEAR, -1).toJdkDate();
        Date yearOnYearDateEnd = DateUtil.offset(dto.getEndTime(), DateField.YEAR, -1).toJdkDate();
        BigDecimal yearOnYearDateValue = ftbPersonnelsOverviewAnalysisMapper.queryTheNumberOfNewcomers(DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDateStart), DatePattern.NORM_MONTH_FORMAT.format(yearOnYearDateEnd), userIdListByOrganizeIds, timeRule);
        List<String> presenceOfPersonnelY= getTheNumberOfPeopleInOffice(yearOnYearDateEnd, userIdListByOrganizeIds);
        int aLongY = presenceOfPersonnelY.size();
        BigDecimal yearOnYear = FtbPersonnelsOverviewAnalysisService.computeDivision(yearOnYearDateValue, aLongY);

        drainVO.setYearOnYear(FtbPersonnelsOverviewAnalysisService.computeDivisionSb(computeDivision.subtract(yearOnYear), yearOnYear, 2));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chainDateStart = DateUtil.offset(dto.getStartTime(), DateField.MONTH, -1).toJdkDate();
        Date chainDateEnd = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        BigDecimal chainDateValue = ftbPersonnelsOverviewAnalysisMapper.queryTheNumberOfNewcomers(DatePattern.NORM_MONTH_FORMAT.format(chainDateStart),
                DatePattern.NORM_MONTH_FORMAT.format(chainDateEnd),
                userIdListByOrganizeIds,
                timeRule);
        List<String> presenceOfPersonnelC = getTheNumberOfPeopleInOffice(chainDateEnd, userIdListByOrganizeIds);
        int aLongC = presenceOfPersonnelC.size();
        BigDecimal annulus = FtbPersonnelsOverviewAnalysisService.computeDivision(chainDateValue, aLongC);
        drainVO.setChainValue(FtbPersonnelsOverviewAnalysisService.computeDivisionSb(computeDivision.subtract(annulus), annulus, 2));
        return drainVO;
    }

    /**
     * 在职人员
     *
     * @param endTime
     * @param userIdListByOrganizeIds
     * @return
     */
    private List<String> getTheNumberOfPeopleInOffice(Date endTime, List<String> userIdListByOrganizeIds) {
        // 在职人员
        return ftbPersonnelsOverviewAnalysisMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(endTime)
                , FtbPersonnelsOverviewAnalysisServiceImpl.ON_THE_JOB_STATUS, userIdListByOrganizeIds);
    }

    @Override
    public List<FtbPersonnelsPeoplePostRatioVO> getOnboardingPostDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeoplePostRatioVO> results = new ArrayList<>();
        // 人事异动入职人数同比环比
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        // 人事异动入职岗位维度
//        List<FtbPersonnelsStaffEmploymentApply> applyList =
//                applyMapper.getOnboardingPostDimension(DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
//                        DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds);
        List<FtbPersonnelsStaffEmploymentApply> applyList =   applyMapper.ListOfOnboardingPositions(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds);
        List<String> userIds = applyList.stream().map(FtbPersonnelsStaffEmploymentApply::getUserId).collect(Collectors.toList());
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIds, UserProvider.getUser().getTenantId());
        List<UserBoundVO> actionResultData = actionResult.getData();
        Map<String, List<UserBoundVO>> stringListMap = actionResultData.stream().collect(Collectors.groupingBy(v->v.getPositionId()+":"+v.getPositionName()));
        stringListMap.forEach((k, v) -> {
            FtbPersonnelsPeoplePostRatioVO ratioVO = new FtbPersonnelsPeoplePostRatioVO();
            String[] split = k.split(":");
            String postId = split[0];
            ratioVO.setPostId(postId);
            ratioVO.setPostName(split[1]);
            Integer totalCount = getTotalCount(postId, dto.getStartTime(), dto.getOrganizationId());
            ratioVO.setTotalCount(totalCount);
            int size = v.size();
            ratioVO.setCurrentCount(size);
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(size, totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    @Override
    public List<FtbPersonnelsPeoplePostRatioVO> getRegularPostDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeoplePostRatioVO> results = new ArrayList<>();
        // 人事异动转正人数同比环比
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        List<FtbPersonnelsRegularManagementVO> managements = regularManagementMapper.queryUserInfoForRegularization(
                DateUtil.beginOfMinute(dto.getStartTime()),
                DateUtil.endOfMonth(dto.getStartTime()), userIdListByOrganizeIds
        );
        Map<String, List<FtbPersonnelsRegularManagementVO>> postMap =
                managements.stream().collect(Collectors.groupingBy(item -> item.getRegularPostId() + ":" + item.getRegularPostName()));
        postMap.forEach((k, v) -> {
            FtbPersonnelsPeoplePostRatioVO ratioVO = new FtbPersonnelsPeoplePostRatioVO();
            String[] split = k.split(":");
            String postId = split[0];
            ratioVO.setPostId(postId);
            ratioVO.setPostName(split[1]);
            Integer totalCount = getTotalCount(postId, dto.getStartTime(), dto.getOrganizationId());
            ratioVO.setTotalCount(totalCount);
            int size = v.size();
            ratioVO.setCurrentCount(size);
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(size, totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    public Integer getTotalCount(String postId, Date startTime, List<String> organizationId) {
        QueryUserBatchDTO userBatchDTO = new QueryUserBatchDTO();
        userBatchDTO.setPositionIds(List.of(postId));
        ActionResult<List<UserBoundVO>> userInfoBatch = v2UserApi.getUserInfoBatch(userBatchDTO);
        if (userInfoBatch.getCode() == 200) {
            DateTime dateTime = DateUtil.endOfMonth(startTime);
            return Math.toIntExact(userInfoBatch.getData().stream().filter(v -> (v.getWorkStatusEnums() != null && v.getEntryDate() != null &&
                    ON_THE_JOB_STATUS.contains(v.getWorkStatusEnums().getCode())) &&
                    dateTime.after(v.getEntryDate()) &&
                    organizationId.contains(v.getOrganizeId())).count());
        }
        return 0;
    }

    @Override
    public List<FtbPersonnelsPeoplePostRatioVO> getTurnoverPostDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeoplePostRatioVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = doEmployeesOfYourOrganization(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        List<FtbPersonnelsTurnoverManagementVO> managements = turnoverManagementMapper.queryUserInfoForTurnover(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds
        );
        List<FtbPersonnelsTurnoverStatisticVO> statisticVOS = managements.stream().map(item -> {
            List<WorkerGroupDataDto> dtos = JSONArray.parseArray(item.getOrganizationInfo(), WorkerGroupDataDto.class);
            WorkerGroupDataDto dataDto = dtos.stream().filter(vo -> vo.getIsPrimaryPosition() || vo.getIsDefault()).findFirst().orElse(new WorkerGroupDataDto());
            FtbPersonnelsTurnoverStatisticVO turnoverStatisticVO = FtbPersonnelsTurnoverStatisticVO.covert(dataDto);
            turnoverStatisticVO.setUserId(item.getUserId());
            turnoverStatisticVO.setUserName(item.getUserName());
            return turnoverStatisticVO;
        }).collect(Collectors.toList());
        Map<String, List<FtbPersonnelsTurnoverStatisticVO>> postMap =
                statisticVOS.stream().collect(Collectors.groupingBy(item -> item.getAffiliatedPosition() + ":" + item.getAffiliatedPositionName()));
        postMap.forEach((k, v) -> {
            FtbPersonnelsPeoplePostRatioVO ratioVO = new FtbPersonnelsPeoplePostRatioVO();
            String[] split = k.split(":");
            String postId = split[0];
            ratioVO.setPostId(postId);
            ratioVO.setPostName(split[1]);
            Integer totalCount = getTotalCount(postId, dto.getStartTime(), dto.getOrganizationId());
            ratioVO.setTotalCount(totalCount);
            int size = v.size();
            ratioVO.setCurrentCount(size);
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(size, totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    @Override
    public List<FtbPersonnelsPeopleInfoRatioVO> getOnboardingStoreDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeopleInfoRatioVO> results = new ArrayList<>();
        // 类型 1部门 2门店 3岗位
        Integer type = dto.getType();
        if (type == 3) {
            List<FtbPersonnelsPeoplePostRatioVO> postDimension = getOnboardingPostDimension(dto);
            return postDimension.stream().map(FtbPersonnelsPeopleInfoRatioVO::covert).collect(Collectors.toList());
        }
        // 人事异动入职人数 门店维度,部门维度
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }

        // 人事异动入职人数 门店维度,部门维度
        List<FtbPersonnelsStaffEmploymentApply> applyList =
                applyMapper.ListOfOnboardingPositions(DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds);
        List<String> userIds = applyList.stream().map(FtbPersonnelsStaffEmploymentApply::getUserId).collect(Collectors.toList());
        Map<String, List<UserBoundVO>> groupingData = getTypeReturnsInfoGroupingData(type, userIds);
        int totalCount = groupingData.values().stream().mapToInt(List::size).sum();
        groupingData.forEach((k, v) -> {
            FtbPersonnelsPeopleInfoRatioVO ratioVO = new FtbPersonnelsPeopleInfoRatioVO();
            String[] split = k.split(":");
            // 名称
            ratioVO.setName(split[1]);
            // 当前数量
            ratioVO.setCurrentCount(v.size());
            // List<String> organizationId = getOrganizationId(List.of(key));
            // 比例
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    @Override
    public List<FtbPersonnelsPeopleInfoRatioVO> getRegularizationStoreDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeopleInfoRatioVO> results = new ArrayList<>();
        // 类型 1部门 2门店 3岗位
        Integer type = dto.getType();
        if (type == 3) {
            List<FtbPersonnelsPeoplePostRatioVO> postDimension = getRegularPostDimension(dto);
            return postDimension.stream().map(FtbPersonnelsPeopleInfoRatioVO::covert).collect(Collectors.toList());
        }
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        List<String> userIds = regularManagementMapper.getRegularizationStoreDimension(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds);
        Map<String, List<UserBoundVO>> groupingData = getTypeReturnsInfoGroupingData(type, userIds);
        int totalCount = groupingData.values().stream().mapToInt(List::size).sum();
        groupingData.forEach((k, v) -> {
            FtbPersonnelsPeopleInfoRatioVO ratioVO = new FtbPersonnelsPeopleInfoRatioVO();
            String[] split = k.split(":");
            // 名称
            ratioVO.setName(split[1]);
            String key = split[0];
            checkTheNumberOfPositions(type, key, ratioVO);
            // 当前数量
            ratioVO.setCurrentCount(v.size());
            // 比例
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    @Override
    public List<FtbPersonnelsPeopleInfoRatioVO> getTurnoverStoreDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeopleInfoRatioVO> results = new ArrayList<>();
        // 类型 1部门 2门店 3岗位
        Integer type = dto.getType();
        if (type == 3) {
            List<FtbPersonnelsPeoplePostRatioVO> postDimension = getTurnoverPostDimension(dto);
            return postDimension.stream().map(FtbPersonnelsPeopleInfoRatioVO::covert).collect(Collectors.toList());
        }
        List<String> userIdListByOrganizeIds = doEmployeesOfYourOrganization(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        List<FtbPersonnelsTurnoverManagementVO> managements = turnoverManagementMapper.queryUserInfoForTurnover(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds
        );
        // 离职人员
        List<String> userIds = managements.stream().map(FtbPersonnelsTurnoverManagementVO::getUserId).collect(Collectors.toList());
        Map<String, List<UserBoundVO>> groupingData = getTypeReturnsInfoGroupingData(type, userIds);
        int totalCount = groupingData.values().stream().mapToInt(List::size).sum();
        groupingData.forEach((k, v) -> {
            FtbPersonnelsPeopleInfoRatioVO ratioVO = new FtbPersonnelsPeopleInfoRatioVO();
            String[] split = k.split(":");
            // 名称
            ratioVO.setName(split[1]);
            String key = split[0];
            checkTheNumberOfPositions(type, key, ratioVO);
            // 当前数量
            ratioVO.setCurrentCount(v.size());
            // 比例
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    /**
     * 扩展人员岗位总数
     *
     * @param type
     * @param key
     * @param ratioVO
     */
    private void checkTheNumberOfPositions(Integer type, String key, FtbPersonnelsPeopleInfoRatioVO ratioVO) {
        if (type == 3) {
            QueryUserBatchDTO userBatchDTO = new QueryUserBatchDTO();
            userBatchDTO.setPositionIds(List.of(key));
            ActionResult<List<UserBoundVO>> userInfoBatch = v2UserApi.getUserInfoBatch(userBatchDTO);
            if (userInfoBatch.getCode() == 200) {
                ratioVO.setTotalCount(userInfoBatch.getData().size());
            }
        }
    }

    @Override
    public List<FtbPersonnelsPeopleInfoRatioVO> getNewHireRateDimension(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeopleInfoRatioVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        if (dto.getType() == 3) {
            List<FtbPersonnelsPeoplePostRatioVO> postDimension = getNewHireRateDimensionPosition(dto);
            return postDimension.stream().map(FtbPersonnelsPeopleInfoRatioVO::covert).collect(Collectors.toList());
        }
        // 新员工定义配置
        FtbPersonnelsRuleConfig ruleConfig = ftbPersonnelsRuleConfigMapper.selectById(1);
        // 新员工离职人数
        Integer timeRule = ruleConfig.getTimeRule();
        Integer type = ruleConfig.getType();
        // 天数
        timeRule = type == 2 ? timeRule * 30 : timeRule;
        // 查询新人人员数
        List<String> newcomerNumUserList = ftbPersonnelsOverviewAnalysisMapper.queryTheNewcomerID(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()),
                userIdListByOrganizeIds, timeRule);
        Integer dtoType = dto.getType();
        Map<String, List<UserBoundVO>> groupingData = getTypeReturnsInfoGroupingData(dtoType, newcomerNumUserList);
        int totalCount = groupingData.values().stream().mapToInt(List::size).sum();
        groupingData.forEach((k, v) -> {
            FtbPersonnelsPeopleInfoRatioVO ratioVO = new FtbPersonnelsPeopleInfoRatioVO();
            String[] split = k.split(":");
            // 名称
            ratioVO.setName(split[1]);
            // 当前数量
            ratioVO.setCurrentCount(v.size());
            List<String> organizationId = getOrganizationId(List.of(split[0]));
            // 比例
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), organizationId.size()));
            results.add(ratioVO);
        });
        return results;
    }

    private List<FtbPersonnelsPeoplePostRatioVO> getNewHireRateDimensionPosition(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeoplePostRatioVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        // 新员工定义配置
        FtbPersonnelsRuleConfig ruleConfig = ftbPersonnelsRuleConfigMapper.selectById(1);
        // 新员工离职人数
        Integer timeRule = ruleConfig.getTimeRule();
        Integer type = ruleConfig.getType();
        // 天数
        timeRule = type == 2 ? timeRule * 30 : timeRule;
        // 查询新人人员数
        List<String> newcomerNumUserList = ftbPersonnelsOverviewAnalysisMapper.queryTheNewcomerID(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()),
                userIdListByOrganizeIds, timeRule);
        Map<String, List<UserBoundVO>> postMap = getTypeReturnsInfoGroupingData(dto.getType(), newcomerNumUserList);
        postMap.forEach((k, v) -> {
            FtbPersonnelsPeoplePostRatioVO ratioVO = new FtbPersonnelsPeoplePostRatioVO();
            String[] split = k.split(":");
            String id = split[0];
            // 名称
            ratioVO.setPostName(split[1]);
            // 当前数量
            ratioVO.setCurrentCount(v.size());
            Integer totalCount = getTotalCount(id, dto.getStartTime(), dto.getOrganizationId());
            ratioVO.setTotalCount(totalCount);
            // 比例
            ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), totalCount));
            results.add(ratioVO);
        });
        return results;
    }

    /**
     * 根据不同type进行统计
     *
     * @param dtoType             1部门 2门店 3岗位
     * @param newcomerNumUserList
     * @return
     */
    public Map<String, List<UserBoundVO>> getTypeReturnsInfoGroupingData(Integer dtoType, List<String> newcomerNumUserList) {
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(newcomerNumUserList, "");
        if (actionResult.getCode() != 200) {
            throw new RuntimeException("获取用户主岗信息失败");
        }
        List<UserBoundVO> data = actionResult.getData();
        //  类型 1部门 2门店 3岗位
        Map<String, List<UserBoundVO>> stringListMap = null;
        switch (dtoType) {
            case 1:
                stringListMap = data.stream().filter(v -> OrganizeCategoryEnums.DEPARTMENT.getCode().equals(v.getOrganizeCategory())).collect(Collectors.groupingBy(v -> v.getOrganizeId() + ":" + v.getOrganizeName()));
                break;
            case 2:
                stringListMap = data.stream().filter(v -> OrganizeCategoryEnums.STORE.getCode().equals(v.getOrganizeCategory())).collect(Collectors.groupingBy(v -> v.getOrganizeId() + ":" + v.getOrganizeName()));
                break;
            case 3:
                stringListMap = data.stream().filter(v->StringUtils.isNotEmpty(v.getPositionName())).collect(Collectors.groupingBy(v -> v.getPositionId() + ":" + v.getPositionName()));
                break;
        }
        return stringListMap;
    }

    /**
     * 所选组织和岗位员工
     */
    private List<String> getOrganizationId(List<String> organizationId) {
        QueryPageUserDTO queryPageUserDTO = new QueryPageUserDTO();
        queryPageUserDTO.setIsPage(false);
        queryPageUserDTO.setOrganizeIds(organizationId);
        queryPageUserDTO.setHaveChildOrganizeId(false);
        ActionResult<PageListVO<UserBoundVO>> pageListVOActionResult = v2UserApi.pagePost(queryPageUserDTO);
        if (pageListVOActionResult.getCode() == 200 && Objects.nonNull(pageListVOActionResult.getData())) {
            return pageListVOActionResult.getData().getList().stream().map(UserBoundVO::getId).collect(Collectors.toList());
        }
        return null;
    }

    /**
     * 人事异动转正人数
     *
     * @param startTime
     * @param endTime
     * @param userIdListByOrganizeIds
     * @param organizationId
     * @return
     */
    private Long generalQueryOfTheNumberOfRegulars(Date startTime, Date endTime, List<String> userIdListByOrganizeIds, List<String> organizationId) {
        LambdaQueryWrapper<FtbPersonnelsRegularManagement> wrapper = Wrappers.lambdaQuery();
        wrapper.in(FtbPersonnelsRegularManagement::getUserId, userIdListByOrganizeIds);
        wrapper.eq(FtbPersonnelsRegularManagement::getEnableMark, 0);
        wrapper.in(FtbPersonnelsRegularManagement::getTransferStatus, 2, 6);
        wrapper.in(FtbPersonnelsRegularManagement::getOrgId, organizationId);
        wrapper.between(FtbPersonnelsRegularManagement::getActualConverDate, DateUtil.beginOfMinute(startTime),
                DateUtil.endOfMonth(endTime));
        return regularManagementMapper.selectCount(wrapper);
    }
    @Override
    public PageListVO<FtbPersonnelsOnboardingDetailVO> getOnboardingDetail(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsOnboardingDetailVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        // 获取入职人员信息
        List<FtbPersonnelsStaffEmploymentApply> applyList =   applyMapper.ListOfOnboardingPositions(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()), userIdListByOrganizeIds);
        // 获取用户信息
        List<String> userIds = applyList.stream().map(FtbPersonnelsStaffEmploymentApply::getUserId).collect(Collectors.toList());
        List<UserBoundVO> data = getUserBoundVOS(dto, userIds);
        if (CollUtil.isEmpty(data)) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        Map<String, UserBoundVO> userMap = data.stream().collect(Collectors.toMap(UserBoundVO::getId, user -> user));
        Map<String, FtbPersonnelsStaffEmploymentApply> applyMap = applyList.stream().collect(Collectors.toMap(FtbPersonnelsStaffEmploymentApply::getUserId, user -> user));
        // 转换为明细VO
        for (UserBoundVO apply : data) {
            FtbPersonnelsOnboardingDetailVO detailVO = new FtbPersonnelsOnboardingDetailVO();
            UserBoundVO user = userMap.get(apply.getId());
            if (user != null) {
                detailVO.setName(user.getUserName());
                detailVO.setEmployeeId(user.getSystemWorkerId());
                detailVO.setOrganization(user.getOrganizeName());
                detailVO.setJobLevel(user.getPositionName());
                detailVO.setJobGrade(user.getGradeName());
            }
            if (applyMap.containsKey(apply.getId())){
                FtbPersonnelsStaffEmploymentApply employmentApply = applyMap.get(apply.getId());
                detailVO.setEntryDate( CovertDateUtils.convertToStringDate(employmentApply.getActualStartDate()));
            }
            results.add(detailVO);
        }
        results.sort(Comparator.comparing(FtbPersonnelsOnboardingDetailVO::getOrganization, Comparator.nullsLast(Comparator.naturalOrder())));
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(dto.getCurrentPage());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotal(results.size());
        return CultivatePage.paginate(results, pagination);
    }

    @Override
    public PageListVO<FtbPersonnelsRegularizationDetailVO> getRegularizationDetail(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsRegularizationDetailVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        // 获取转正人员信息
        List<FtbPersonnelsRegularManagementVO> managements = regularManagementMapper.queryUserInfoForRegularization(
                DateUtil.beginOfMinute(dto.getStartTime()),
                DateUtil.endOfMonth(dto.getStartTime()), userIdListByOrganizeIds
        );
        // 获取用户信息
        List<String> userIds = managements.stream().map(FtbPersonnelsRegularManagementVO::getUserId).collect(Collectors.toList());
        List<UserBoundVO> data = getUserBoundVOS(dto, userIds);
        if (CollUtil.isEmpty(data)) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        Map<String, UserBoundVO> userMap = data.stream().collect(Collectors.toMap(UserBoundVO::getId, user -> user));
        // 转换为明细VO
        for (FtbPersonnelsRegularManagementVO management : managements) {
            FtbPersonnelsRegularizationDetailVO detailVO = new FtbPersonnelsRegularizationDetailVO();
            UserBoundVO user = userMap.get(management.getUserId());
            if (user != null) {
                detailVO.setName(user.getUserName());
                detailVO.setEmployeeId(user.getSystemWorkerId());
                detailVO.setOrganization(user.getOrganizeName());
                detailVO.setJobLevel(user.getPositionName());
                detailVO.setJobGrade(user.getGradeName());
            }
            detailVO.setRegularizationDate( CovertDateUtils.convertToStringDate(management.getActualConverDate()));
            results.add(detailVO);
        }
        results.sort(Comparator.comparing(FtbPersonnelsRegularizationDetailVO::getOrganization, Comparator.nullsLast(Comparator.naturalOrder())));
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(dto.getCurrentPage());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotal(results.size());
        return CultivatePage.paginate(results, pagination);
    }


    /**
     * 获取组织下员工ID集合
     *
     * @param orgIds
     * @return
     */
    private List<String> doEmployeesOfYourOrganization(List<String> orgIds, String[]... postId) {
        if (CollUtil.isNotEmpty(orgIds)) {
            LambdaQueryWrapper<FtbPersonnelsTurnoverManagement> wrapper = Wrappers.lambdaQuery();
            wrapper.eq(FtbPersonnelsTurnoverManagement::getEnableMark, 0);
            wrapper.eq(FtbPersonnelsTurnoverManagement::getWorkingCondition, "305");
            List<FtbPersonnelsTurnoverManagement> managements = turnoverManagementMapper.selectList(wrapper);
            List<String> postIds;
            if (ObjectUtil.isNotEmpty(postId)) {
                postIds = Arrays.stream(postId).flatMap(Arrays::stream).collect(Collectors.toList());
            } else {
                postIds = null;
            }
            if (CollUtil.isNotEmpty(orgIds) && CollUtil.isEmpty(postIds))
                return managements.stream().filter(vo -> StringUtils.isNotEmpty(vo.getOrganizationInfo()))
                        .filter(vo -> CollUtil.isNotEmpty(JSONObject.parseArray(vo.getOrganizationInfo(), WorkerGroupDataDto.class)
                                .stream().map(WorkerGroupDataDto::getAffiliatedOrg).collect(Collectors.toList()).stream().filter(orgIds::contains).collect(Collectors.toList()))
                        ).map(FtbPersonnelsTurnoverManagement::getUserId).collect(Collectors.toList());

            if (CollUtil.isNotEmpty(orgIds) && CollUtil.isNotEmpty(postIds))
                return managements.stream().filter(vo -> StringUtils.isNotEmpty(vo.getOrganizationInfo()))
                        .filter(vo -> CollUtil.isNotEmpty(
                                JSONObject.parseArray(
                                                vo.getOrganizationInfo(), WorkerGroupDataDto.class)
                                        .stream().filter(po -> {
                                            if (!orgIds.contains(po.getAffiliatedOrg())) return false;
                                            assert postIds != null;
                                            return postIds.contains(po.getAffiliatedPosition());
                                        }).collect(Collectors.toList()))
                        ).map(FtbPersonnelsTurnoverManagement::getUserId).collect(Collectors.toList());
        }
        return null;
    }

    @Override
    public PageListVO<FtbPersonnelsNewHireRateDetailVO> getNewHireRateDetail(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsNewHireRateDetailVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = getOrganizationId(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        // 获取新人规则天数
        LambdaQueryWrapper<FtbPersonnelsRuleConfig> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsRuleConfig::getEnableMark, 0);
        FtbPersonnelsRuleConfig ruleConfig = ftbPersonnelsRuleConfigMapper.selectOne(wrapper);
        if (ruleConfig == null) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        Integer type = ruleConfig.getType();
        Integer timeRule = type == 1 ? ruleConfig.getTimeRule() : ruleConfig.getTimeRule() * 30;

        // 查询新人人员信息
        List<FtbPersonnelsStaffEmploymentApply> applyList = ftbPersonnelsOverviewAnalysisMapper.queryTheNumberOfNewcomersList(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime()),
                userIdListByOrganizeIds,
                timeRule);

        // 获取用户信息
        List<String> userIds = applyList.stream().map(FtbPersonnelsStaffEmploymentApply::getUserId).collect(Collectors.toList());
        List<UserBoundVO> data = getUserBoundVOS(dto, userIds);
        if (CollUtil.isEmpty(data)) {
            return CultivatePage.paginate(results, new PaginationVO());
        }
        Map<String, UserBoundVO> userMap = data.stream().collect(Collectors.toMap(UserBoundVO::getId, user -> user));
        // 转换为明细 VO
        for (FtbPersonnelsStaffEmploymentApply apply : applyList) {
            FtbPersonnelsNewHireRateDetailVO detailVO = new FtbPersonnelsNewHireRateDetailVO();
            UserBoundVO user = userMap.get(apply.getUserId());
            if (user != null) {
                detailVO.setName(user.getUserName());
                detailVO.setEmployeeId(user.getSystemWorkerId());
                detailVO.setOrganization(user.getOrganizeName());
                detailVO.setJobLevel(user.getPositionName());
                detailVO.setJobGrade(user.getGradeName());
                // 计算司龄（月）
                if (apply.getActualStartDate() != null) {
                    String string = CompanyAgeUtil.calculateSeniority(apply.getActualStartDate(), new Date());
                    detailVO.setSeniority(string);
                }
            }
            results.add(detailVO);
        }
        results.sort(Comparator.comparing(FtbPersonnelsNewHireRateDetailVO::getOrganization, Comparator.nullsLast(Comparator.naturalOrder())));
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(dto.getCurrentPage());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotal(results.size());
        return  CultivatePage.paginate(results, pagination);
    }

    private List<UserBoundVO> getUserBoundVOS(FtbPersonnlesAnalysisDTO dto, List<String> userIds) {
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(userIds, UserProvider.getUser().getTenantId());
        if (actionResult.getCode() != 200) {
            return null;
        }
        List<UserBoundVO> data = actionResult.getData();
        // 1部门 2门店 3岗位
        if (dto.getType() == 1) {
            data = data.stream().filter(v -> OrganizeCategoryEnums.DEPARTMENT.getCode().equals(v.getOrganizeCategory())).collect(Collectors.toList());
        } else if (dto.getType() == 2) {
            data = data.stream().filter(v -> OrganizeCategoryEnums.STORE.getCode().equals(v.getOrganizeCategory())).collect(Collectors.toList());
        }
        return data;
    }

    @Override
    public void getNewHireRateDetailExport(FtbPersonnlesAnalysisDTO dto, HttpServletResponse response) {
        dto.setPageSize(-1);
        List<FtbPersonnelsNewHireRateDetailVO> dataList = getNewHireRateDetail(dto).getList();
        exportExcel(response, "新人率占比明细", dataList, FtbPersonnelsNewHireRateDetailVO.class);
    }


    @Override
    public void getOnboardingDetailExport(FtbPersonnlesAnalysisDTO dto, HttpServletResponse response) {
        dto.setPageSize(-1);
        List<FtbPersonnelsOnboardingDetailVO> dataList = getOnboardingDetail(dto).getList();
        exportExcel(response, "入职明细", dataList, FtbPersonnelsOnboardingDetailVO.class);
    }

    @Override
    public void getRegularizationDetailExport(FtbPersonnlesAnalysisDTO dto, HttpServletResponse response) {
        dto.setPageSize(-1);
        List<FtbPersonnelsRegularizationDetailVO> dataList = getRegularizationDetail(dto).getList();
        exportExcel(response, "转正明细", dataList, FtbPersonnelsRegularizationDetailVO.class);
    }

    /**
     * 导出 Excel 文件
     *
     * @param response HTTP 响应
     * @param fileName 文件名
     * @param dataList 数据列表
     * @param clazz VO 类
     */
    @SneakyThrows
    private <T> void exportExcel(HttpServletResponse response, String fileName, List<T> dataList, Class<T> clazz) {
        EasyExcelUtils.exportExcel(response, fileName,  dataList,clazz);
    }

}
