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.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.po.FtbPersonnelsStaffRoster;
import jnpf.model.personnels.vo.analysis.*;
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.FtbPersonnelChangesMapper;
import jnpf.personnels.mapper.FtbPersonnelsOverviewAnalysisMapper;
import jnpf.personnels.mapper.FtbPersonnelsStaffRosterMapper;
import jnpf.personnels.service.FtbPersonnelChangesService;
import jnpf.personnels.service.FtbPersonnelsOverviewAnalysisService;
import jnpf.util.excel.EasyExcelUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class FtbPersonnelChangesServiceImpl implements FtbPersonnelChangesService {

    @Resource
    private FtbPersonnelChangesMapper ftbPersonnelChangesMapper;

    @Resource
    private FtbPersonnelsStaffRosterMapper ftbPersonnelsStaffRosterMapper;

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

    @Autowired
    private V2UserApi v2UserApi;

    @Override
    public FtbPersonnlesBrainShopAdjustmentVO getBrainDrainCorrectRateShopAdjustment(FtbPersonnlesAnalysisDTO dto) {
        FtbPersonnlesBrainShopAdjustmentVO ftbPersonnlesBrainShopAdjustmentVO = new FtbPersonnlesBrainShopAdjustmentVO();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return ftbPersonnlesBrainShopAdjustmentVO;
        }
        // 调店人数
        BigDecimal numberOfPeopleAdjustingTheStore = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStore(DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIdListByOrganizeIds, 3);
        ftbPersonnlesBrainShopAdjustmentVO.setRegularNum(numberOfPeopleAdjustingTheStore);
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearStartDate = DateUtil.offset(dto.getStartTime(), DateField.YEAR, -1).toJdkDate();
        Date yearOnYearEndDate = DateUtil.offset(dto.getStartTime(), DateField.YEAR, -1).toJdkDate();
        BigDecimal yearOnYearDateValue = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStore(DatePattern.NORM_MONTH_FORMAT.format(yearOnYearStartDate),
                DatePattern.NORM_MONTH_FORMAT.format(yearOnYearEndDate)
                , userIdListByOrganizeIds, 3);
        ftbPersonnlesBrainShopAdjustmentVO.setYearOnYear(FtbPersonnelsOverviewAnalysisService.computeDivision(numberOfPeopleAdjustingTheStore.subtract(yearOnYearDateValue), yearOnYearDateValue)
                .setScale(0, RoundingMode.HALF_UP));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chainStartDate = DateUtil.offset(dto.getStartTime(), DateField.MONTH, -1).toJdkDate();
        Date chainEndDate = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        BigDecimal chainDateValue = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStore(
                DatePattern.NORM_MONTH_FORMAT.format(chainStartDate),
                DatePattern.NORM_MONTH_FORMAT.format(chainEndDate), userIdListByOrganizeIds, 3);
        ftbPersonnlesBrainShopAdjustmentVO.setAnnulus(FtbPersonnelsOverviewAnalysisService.computeDivision(numberOfPeopleAdjustingTheStore.subtract(chainDateValue), chainDateValue)
                .setScale(0, RoundingMode.HALF_UP));
        return ftbPersonnlesBrainShopAdjustmentVO;
    }

    @Override
    public FtbPersonnlesBrainShopAdjustmentVO getBrainDrainCorrectRateTransferPost(FtbPersonnlesAnalysisDTO dto) {
        FtbPersonnlesBrainShopAdjustmentVO ftbPersonnlesBrainShopAdjustmentVO = new FtbPersonnlesBrainShopAdjustmentVO();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return ftbPersonnlesBrainShopAdjustmentVO;
        }
        // 调店人数
        BigDecimal numberOfPeopleAdjustingTheStore = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStore(DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIdListByOrganizeIds, 0);
        ftbPersonnlesBrainShopAdjustmentVO.setRegularNum(numberOfPeopleAdjustingTheStore);
        // 同比 （本期数 - 同期数） / 同期数 × 100%
        Date yearOnYearStartDate = DateUtil.offset(dto.getStartTime(), DateField.YEAR, -1).toJdkDate();
        Date yearOnYearEndDate = DateUtil.offset(dto.getStartTime(), DateField.YEAR, -1).toJdkDate();
        BigDecimal yearOnYearDateValue = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStore(DatePattern.NORM_MONTH_FORMAT.format(yearOnYearStartDate),
                DatePattern.NORM_MONTH_FORMAT.format(yearOnYearEndDate)
                , userIdListByOrganizeIds, 0);
        ftbPersonnlesBrainShopAdjustmentVO.setYearOnYear(FtbPersonnelsOverviewAnalysisService.computeDivision(numberOfPeopleAdjustingTheStore.subtract(yearOnYearDateValue), yearOnYearDateValue)
                .setScale(0, RoundingMode.HALF_UP));
        // 环比 （本期数 - 上期数） / 上期数 × 100%
        Date chainStartDate = DateUtil.offset(dto.getStartTime(), DateField.MONTH, -1).toJdkDate();
        Date chainEndDate = DateUtil.offset(dto.getEndTime(), DateField.MONTH, -1).toJdkDate();
        BigDecimal chainDateValue = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStore(
                DatePattern.NORM_MONTH_FORMAT.format(chainStartDate),
                DatePattern.NORM_MONTH_FORMAT.format(chainEndDate), userIdListByOrganizeIds, 0);
        ftbPersonnlesBrainShopAdjustmentVO.setAnnulus(FtbPersonnelsOverviewAnalysisService.computeDivision(numberOfPeopleAdjustingTheStore.subtract(chainDateValue), chainDateValue)
                .setScale(0, RoundingMode.HALF_UP));
        return ftbPersonnlesBrainShopAdjustmentVO;
    }

    @Override
    public List<FtbPersonnelsPeopleTransferRatioVO> getRegularizationStoreDimensionShopAdjustment(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeopleTransferRatioVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        // 类型 1 部门 2 门店 3 岗位
        Integer type = dto.getType();
        List<String> userIds = ftbPersonnelChangesMapper.departmentHeadcountRatio(DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIdListByOrganizeIds, 3);
        Map<String, List<UserBoundVO>> groupingData = getTypeReturnsInfoGroupingData(type, userIds);
        int totalCount = groupingData.values().stream().mapToInt(List::size).sum();
        groupingData.forEach((k, v) -> {
            FtbPersonnelsPeopleTransferRatioVO ratioVO = new FtbPersonnelsPeopleTransferRatioVO();
            String[] split = k.split(":");
            // 名称
            ratioVO.setName(split[1]);
            String key = split[0];
            checkTheNumberOfPositions(type, key, ratioVO, dto.getStartTime(), dto.getOrganizationId());
            // 当前数量
            ratioVO.setNumberOfPeople(BigDecimal.valueOf(v.size()));
            // 比例
            if (type == 3) {
                ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), ratioVO.getTotalCount()));
            } else {
                ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), totalCount));
            }
            results.add(ratioVO);
        });
        return results;
    }
    @Override
    public List<FtbPersonnelsPeopleTransferRatioVO> getRegularizationStoreDimensionTransferPost(FtbPersonnlesAnalysisDTO dto) {
        List<FtbPersonnelsPeopleTransferRatioVO> results = new ArrayList<>();
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return results;
        }
        // 类型 1部门 2门店 3岗位
        Integer type = dto.getType();
        List<String> userIds = ftbPersonnelChangesMapper.departmentHeadcountRatio(
                DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIdListByOrganizeIds, 0);
        Map<String, List<UserBoundVO>> groupingData = getTypeReturnsInfoGroupingData(type, userIds);
        int totalCount = groupingData.values().stream().mapToInt(List::size).sum();
        groupingData.forEach((k, v) -> {
            FtbPersonnelsPeopleTransferRatioVO ratioVO = new FtbPersonnelsPeopleTransferRatioVO();
            String[] split = k.split(":");
            // 名称
            ratioVO.setName(split[1]);
            String key = split[0];
            checkTheNumberOfPositions(type, key, ratioVO, dto.getStartTime(), dto.getOrganizationId());
            // 当前数量
            ratioVO.setNumberOfPeople(BigDecimal.valueOf(v.size()));
            // 比例
            if (type == 3) {
                ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), ratioVO.getTotalCount()));
            } else {
                ratioVO.setRatio(FtbPersonnelsOverviewAnalysisService.computeDivision(v.size(), totalCount));
            }
            results.add(ratioVO);
        });
        return results;
    }

    @Override
    public PageListVO<FtbPersonnelsShopAdjustmentDetailsVO> shopAdjustmentDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<FtbPersonnelsShopAdjustmentDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<UserBoundVO> typeReturnsInfoData = getTypeReturnsInfoData(dto.getType(), userIdListByOrganizeIds);
        List<String> userIds = typeReturnsInfoData.stream().map(UserBoundVO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userIds)) {
            return result;
        }
        List<FtbPersonnelsShopAdjustmentDetailsVO> resultList = ftbPersonnelChangesMapper.numberOfPeopleAdjustingTheStoreList(DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIds, 3);
        if (CollUtil.isEmpty(resultList)) {
            return result;
        }
        Map<String, String> employeeIDQuery = employeeIDQuery(userIds);
        Map<String, UserBoundVO> userBoundVOMap = typeReturnsInfoData.stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        resultList.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setAFOrganization(userBoundVO.getOrganizeName());
                a.setAFPosition(userBoundVO.getPositionName());
                a.setAFRank(userBoundVO.getGradeName());
                a.setUserName(userBoundVO.getUserName());
                a.setEmployeeId(employeeIDQuery.getOrDefault(a.getUserId(),""));
            }
        });
        result.getPagination().setTotal(resultList.size());
        // 按照组织排序
        resultList.sort(Comparator.comparing(FtbPersonnelsShopAdjustmentDetailsVO::getAFOrganization));
        result.setList(resultList);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<FtbPersonnelsShopAdjustmentDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(),resultList.size());
            return CultivatePage.paginate(resultList, page);
        }
        return result;
    }

    @Override
    public void shopAdjustmentDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<FtbPersonnelsShopAdjustmentDetailsVO> pageListVO = shopAdjustmentDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "调店人数及占比", pageListVO.getList(), FtbPersonnelsShopAdjustmentDetailsVO.class);
    }

    @Override
    public PageListVO<FtbPersonnelsPostAdjustmentDetailsVO> postAdjustmentDetails(FtbPersonnlesAnalysisDTO dto) {
        PageListVO<FtbPersonnelsPostAdjustmentDetailsVO> result = new PageListVO<>();
        result.setPagination(initPaginationVO(dto));
        result.setList(new ArrayList<>());
        List<String> userIdListByOrganizeIds = selectedOrganizationAndPositionEmployees(dto.getOrganizationId());
        if (CollUtil.isEmpty(userIdListByOrganizeIds)) {
            return result;
        }
        List<UserBoundVO> typeReturnsInfoData = getTypeReturnsInfoData(dto.getType(), userIdListByOrganizeIds);
        List<String> userIds = typeReturnsInfoData.stream().map(UserBoundVO::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(userIds)) {
            return result;
        }
        List<FtbPersonnelsPostAdjustmentDetailsVO> resultList = ftbPersonnelChangesMapper.numberOfPeopleAdjustingThePostList(DatePattern.NORM_MONTH_FORMAT.format(dto.getStartTime()),
                DatePattern.NORM_MONTH_FORMAT.format(dto.getEndTime())
                , userIds, 0);
        if (CollUtil.isEmpty(resultList)) {
            return result;
        }
        Map<String, String> employeeIDQuery = employeeIDQuery(userIds);
        Map<String, UserBoundVO> userBoundVOMap = typeReturnsInfoData.stream().collect(Collectors.toMap(UserBoundVO::getId, Function.identity()));
        resultList.forEach(a -> {
            UserBoundVO userBoundVO = userBoundVOMap.get(a.getUserId());
            if (Objects.nonNull(userBoundVO)) {
                a.setOrganization(userBoundVO.getOrganizeName());
                a.setPosition(userBoundVO.getPositionName());
                a.setRank(userBoundVO.getGradeName());
                a.setUserName(userBoundVO.getUserName());
                a.setEmployeeId(employeeIDQuery.getOrDefault(a.getUserId(), ""));
            }
        });
        result.getPagination().setTotal(resultList.size());
        // 按照组织排序
        resultList.sort(Comparator.comparing(FtbPersonnelsPostAdjustmentDetailsVO::getOrganization));
        result.setList(resultList);
        // 分页
        if (dto.getPageSize() != -1) {
            Page<FtbPersonnelsPostAdjustmentDetailsVO> page = Page.of(dto.getCurrentPage(), dto.getPageSize(),resultList.size());
            return CultivatePage.paginate(resultList, page);
        }
        return result;
    }

    @Override
    public void postAdjustmentDetailsExport(FtbPersonnlesAnalysisDTO dto) throws IOException {
        dto.setPageSize(-1);
        PageListVO<FtbPersonnelsPostAdjustmentDetailsVO> pageListVO = postAdjustmentDetails(dto);
        EasyExcelUtils.exportExcel(getResponse(), "调岗人数分布", pageListVO.getList(), FtbPersonnelsPostAdjustmentDetailsVO.class);
    }


    /**
     * 所选组织和岗位员工
     */
    private List<String> selectedOrganizationAndPositionEmployees(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 type
     * @param key
     * @param ratioVO
     */
    private void checkTheNumberOfPositions(Integer type, String key, FtbPersonnelsPeopleTransferRatioVO ratioVO, Date startTime, List<String> organizationId) {
        if (type == 3) {
            QueryUserBatchDTO userBatchDTO = new QueryUserBatchDTO();
            userBatchDTO.setPositionIds(List.of(key));
            ActionResult<List<UserBoundVO>> userInfoBatch = v2UserApi.getUserInfoBatch(userBatchDTO);
            if (userInfoBatch.getCode() == 200) {
                Date chainStartDate = DateUtil.endOfMonth(startTime);
                List<UserBoundVO> newUserInfoBatch = userInfoBatch.getData().stream()
                        .filter(v -> Objects.nonNull(v.getWorkStatusEnums()) && Objects.nonNull(v.getEntryDate())
                                && ON_THE_JOB_STATUS.contains(v.getWorkStatusEnums().getCode())
                                && v.getEntryDate().before(chainStartDate) && organizationId.contains(v.getOrganizeId()))
                        .collect(Collectors.toList());
                ratioVO.setTotalCount(BigDecimal.valueOf(newUserInfoBatch.size()));
            }
        }
    }

    /**
     * 根据不同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, null);
        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().collect(Collectors.groupingBy(v -> v.getPositionId() + ":" + v.getPositionName()));
                break;
        }
        return stringListMap;
    }

    public List<UserBoundVO> getTypeReturnsInfoData(Integer dtoType, List<String> newcomerNumUserList) {
        ActionResult<List<UserBoundVO>> actionResult = v2UserApi.getUserPrimaryBoundBatch(newcomerNumUserList, null);
        if (actionResult.getCode() != 200) {
            throw new RuntimeException("获取用户主岗信息失败");
        }
        List<UserBoundVO> data = actionResult.getData();
        //  类型 1部门 2门店 3岗位
        List<UserBoundVO> stringListMap = null;
        switch (dtoType) {
            case 1:
                stringListMap = data.stream().filter(v -> OrganizeCategoryEnums.DEPARTMENT.getCode().equals(v.getOrganizeCategory())).collect(Collectors.toList());
                break;
            case 2:
                stringListMap = data.stream().filter(v -> OrganizeCategoryEnums.STORE.getCode().equals(v.getOrganizeCategory())).collect(Collectors.toList());
                break;
            case 3:
                stringListMap = new ArrayList<>(data);
                break;
        }
        return stringListMap;
    }

    private PaginationVO initPaginationVO(CultivatePage dto) {
        PaginationVO pagination = new PaginationVO();
        pagination.setCurrentPage(dto.getCurrentPage());
        pagination.setPageSize(dto.getPageSize());
        pagination.setTotal(0);
        return pagination;
    }

    public static HttpServletResponse getResponse() {
        // 从当前threadlocal中获取到
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        return servletRequestAttributes.getResponse();
    }
    private Map<String,String> employeeIDQuery(List<String> userIds) {
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> wrapper = Wrappers.lambdaQuery();
        wrapper.select(FtbPersonnelsStaffRoster::getUserId,FtbPersonnelsStaffRoster::getSystemWokerId);
        wrapper.in(FtbPersonnelsStaffRoster::getUserId,userIds);
        List<FtbPersonnelsStaffRoster> staffRosters = ftbPersonnelsStaffRosterMapper.selectList(wrapper);
        return staffRosters.stream().collect(Collectors.toMap(FtbPersonnelsStaffRoster::getUserId, FtbPersonnelsStaffRoster::getSystemWokerId));
    }
}

