package jnpf.cultivate.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import jnpf.cultivate.mapper.FtbCultivateStatisticsMapper;
import jnpf.cultivate.service.CultivateIdentifyApplyService;
import jnpf.cultivate.service.FtbCultivateExamUserService;
import jnpf.cultivate.service.FtbCultivateStatisticsService;
import jnpf.cultivate.utils.UserApiV2Util;
import jnpf.model.cultivate.dto.statistics.FtbCultivateStatisticsDTO;
import jnpf.model.cultivate.resp.ExamStatisticsVo;
import jnpf.model.cultivate.resp.UserRankingVo;
import jnpf.model.cultivate.v2.statistics.V2CultivateLineNumDto;
import jnpf.model.cultivate.vo.identify.IdentifyStatisticsForNewVo;
import jnpf.model.cultivate.vo.identify.IdentifyTopVo;
import jnpf.model.cultivate.vo.statistics.FtbCultivateStatisticsVO;
import jnpf.model.cultivate.vo.statistics.NumberOfTrainingSessions;
import jnpf.model.cultivate.vo.statistics.NumberofAppSessions;
import jnpf.permission.UserApi;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.organzie.OrganizeManagerFilterNodeVO;
import jnpf.permission.vo.v2.organzie.OrganizeManagerNodeVO;
import jnpf.permission.vo.v2.user.UserPageListVO;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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

@Service
@Slf4j
public class FtbCultivateStatisticsServiceImpl implements FtbCultivateStatisticsService {

    @Resource
    private FtbCultivateStatisticsMapper ftbCultivateStatisticsMapper;
    @Autowired
    private UserApi userApi;
    @Resource
    private FtbCultivateExamUserService examUserService;
    @Resource
    private CultivateIdentifyApplyService applyService;
    @Autowired
    private UserApiV2Util userApiV2Util;

    @Override
    public NumberOfTrainingSessions getNumberOfTraineesStatistics(FtbCultivateStatisticsDTO dto) {
        NumberOfTrainingSessions number = new NumberOfTrainingSessions();
        if (CollectionUtils.isEmpty(dto.getUserIds())) {
            return number;
        }
        FtbCultivateStatisticsDTO ftbCultivateStatisticsDTO = new FtbCultivateStatisticsDTO();
        ftbCultivateStatisticsDTO.setUserIds(dto.getUserIds());
        ftbCultivateStatisticsDTO.setDateType(dto.getDateType());
        ftbCultivateStatisticsDTO.setOrgId(dto.getOrgId());
        // 学习数
        number.setNumOfTrainees(ftbCultivateStatisticsMapper.numOfTraineesV2(dto));
        // 累计学习人数
        number.setCumulativeNumberOfTrainees(ftbCultivateStatisticsMapper.numOfTraineesV2(ftbCultivateStatisticsDTO));
        // 学习课程数
        number.setNumberOfStudyCourses(ftbCultivateStatisticsMapper.numberOfStudyCoursesV2(dto));
        // 累计学习课程数
        number.setCumulativeNumberOfCoursesTaken(ftbCultivateStatisticsMapper.numberOfStudyCoursesV2(ftbCultivateStatisticsDTO));
        // 时长
        number.setDuration(ftbCultivateStatisticsMapper.accumulatedTimeV2(dto));
        // 累计时长
        Integer accumulatedTime = ftbCultivateStatisticsMapper.accumulatedTimeV2(ftbCultivateStatisticsDTO);
        number.setAccumulatedTime(accumulatedTime);
        // 完课率 已学习/学习中+已学习
        Integer courseCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRateV2(dto, List.of(1));
        Integer denominatorCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRateV2(dto, List.of(0, 1));
        number.setCourseCompletionRate(getCompletionRate(courseCompletionRate, denominatorCompletionRate));
        // 总完课率
        Integer completionRate = ftbCultivateStatisticsMapper.courseCompletionRateV2(ftbCultivateStatisticsDTO, List.of(1));
        Integer denominatorOverallCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRateV2(ftbCultivateStatisticsDTO, List.of(0, 1));
        number.setOverallCourseCompletionRate(getCompletionRate(completionRate, denominatorOverallCompletionRate));
        return number;
    }

    @Override
    public List<FtbCultivateStatisticsVO.PopularCourses> getPopularCourses(FtbCultivateStatisticsDTO dto) {
        List<String> userIds = dto.getUserIds();
        if (CollectionUtils.isEmpty(userIds)) {
            return null;
        }
        return ftbCultivateStatisticsMapper.getPopularCourses(dto);
    }

    @Override
    public List<FtbCultivateStatisticsVO.LineChartCumulativeLearners> numberOfStudentsLineGraph(FtbCultivateStatisticsDTO dto) {
        List<FtbCultivateStatisticsVO.LineChartCumulativeLearners> result = new ArrayList<>();
        if (dto.getStartTime() == null || dto.getEndTime() == null) {
            return result;
        }
        // 月度，统计每一天的
        if (dto.getDateType() == 1) {
            long betweenDay = DateUtil.betweenDay(dto.getStartTime(), dto.getEndTime(), true);
            for (int i = 0; i <= betweenDay; i++) {
                // 多线程查询
                Date offsetDay = DateUtil.offsetDay(dto.getStartTime(), i).toJdkDate();
                Date startTime = DateUtil.beginOfDay(offsetDay);
                Date endTime = DateUtil.endOfDay(offsetDay);
                doLearnDataProcessing(dto, startTime, endTime, offsetDay, result, "yyyy-MM-dd");
            }
        }
        // 季度，统计每个月的
        if (dto.getDateType() == 2) {
            long betweenMonth = DateUtil.betweenMonth(dto.getStartTime(), dto.getEndTime(), true);
            for (int i = 0; i <= betweenMonth; i++) {
                Date offsetDay = DateUtil.offsetMonth(dto.getStartTime(), i).toJdkDate();
                Date startTime = DateUtil.beginOfMonth(offsetDay);
                Date endTime = DateUtil.endOfMonth(offsetDay);
                doLearnDataProcessing(dto, startTime, endTime, offsetDay, result, "yyyy-MM");
            }
        }
        // 年度，统计每个月的
        if (dto.getDateType() == 3) {
            for (int i = 0; i <= 11; i++) {
                Date offsetDay = DateUtil.offsetMonth(dto.getStartTime(), i).toJdkDate();
                Date startTime = DateUtil.beginOfMonth(offsetDay);
                Date endTime = DateUtil.endOfMonth(offsetDay);
                doLearnDataProcessing(dto, startTime, endTime, offsetDay, result, "yyyy-MM");
            }
        }
        return result;
    }

    private void doLearnDataProcessing(FtbCultivateStatisticsDTO dto, Date startTime, Date endTime, Date offsetDay,
                                       List<FtbCultivateStatisticsVO.LineChartCumulativeLearners> result, String format) {
        FtbCultivateStatisticsDTO ftbCultivateStatisticsDTO = new FtbCultivateStatisticsDTO();
        ftbCultivateStatisticsDTO.setUserIds(dto.getUserIds());
        ftbCultivateStatisticsDTO.setDateType(dto.getDateType());
        ftbCultivateStatisticsDTO.setOrgId(dto.getOrgId());
        ftbCultivateStatisticsDTO.setStartTime(startTime);
        ftbCultivateStatisticsDTO.setEndTime(endTime);
        FtbCultivateStatisticsVO.LineChartCumulativeLearners lineChartCumulativeLearners = new FtbCultivateStatisticsVO.LineChartCumulativeLearners();
        lineChartCumulativeLearners.setDate(DateUtil.format(offsetDay, format));
        if (CollectionUtils.isEmpty(dto.getUserIds())) {
            // 学习人数
            lineChartCumulativeLearners.setNumberOfStudents(0);
            // 学习时长
            lineChartCumulativeLearners.setStudyDuration(0);
        } else {
            V2CultivateLineNumDto numDto =ftbCultivateStatisticsMapper.queryStudyUserNumAndTimeV2(ftbCultivateStatisticsDTO);
            // 学习人数
            lineChartCumulativeLearners.setNumberOfStudents(numDto.getNumberOfStudents());
            // 学习时长
            lineChartCumulativeLearners.setStudyDuration(numDto.getStudyDuration());
        }
        result.add(lineChartCumulativeLearners);
    }

    @Override
    public List<FtbCultivateStatisticsVO.TopMembers> getTopMembers(FtbCultivateStatisticsDTO dto, Integer rankingType) {
        if (CollectionUtils.isEmpty(dto.getUserIds())) {
            return new ArrayList<>();
        }
        if (rankingType == 1) {
            List<FtbCultivateStatisticsVO.TopMembers> result = ftbCultivateStatisticsMapper.getTopMembers(dto);
            Map<String, UserEntity> userEntityMap = userApiV2Util.getUserNameAndCopyForUserIds(
                    result.stream()
                            .map(FtbCultivateStatisticsVO.TopMembers::getOrdinate)
                            .collect(Collectors.toList())
            );

            result.forEach(item -> {
                UserEntity userEntity = userEntityMap.get(item.getOrdinate());
                item.setOrdinate(userEntity != null ? userEntity.getRealName() : item.getOrdinate());
            });
            return result;
        } else if (rankingType == 2) {
            List<UserRankingVo> rankingList = examUserService.statisticsExamRankingListNoPower(dto);
            return rankingList.stream().map(item -> {
                FtbCultivateStatisticsVO.TopMembers topMembers = new FtbCultivateStatisticsVO.TopMembers();
                topMembers.setAbscissa(item.getScore());
                topMembers.setOrdinate(item.getUserName());
                return topMembers;
            }).collect(Collectors.toList());
        } else if (rankingType == 3) {
            List<IdentifyTopVo> identifyTop = applyService.getIdentifyTop(dto);
            return identifyTop.stream().map(item -> {
                FtbCultivateStatisticsVO.TopMembers topMembers = new FtbCultivateStatisticsVO.TopMembers();
                topMembers.setAbscissa(item.getPassRate().toString());
                topMembers.setOrdinate(item.getUserName());
                return topMembers;
            }).collect(Collectors.toList());

        }
        return null;
    }

    @Override
    public NumberofAppSessions trainingStatisticsV2(FtbCultivateStatisticsDTO dto) {
        NumberofAppSessions numberofAppSessions = new NumberofAppSessions();
        List<String> organizeIdsAdnChildByUserId = processWithOrgIds(dto);
        if (CollUtil.isEmpty(organizeIdsAdnChildByUserId)) {
            return numberofAppSessions;
        }
        List<UserPageListVO> listFeign = userApiV2Util.getUserListForOrgIds(organizeIdsAdnChildByUserId, null);
        if (CollUtil.isEmpty(listFeign)) {
            return numberofAppSessions;
        }

        List<String> userIds = listFeign.stream().map(UserPageListVO::getId).distinct().collect(Collectors.toList());
        dto.setUserIds(userIds);

        // 数据统计计算
        calculateStatistics(dto, numberofAppSessions);

        return numberofAppSessions;
    }

    /**
     * 处理有多个组织ID的情况
     */
    private List<String> processWithOrgIds(FtbCultivateStatisticsDTO dto) {
        List<OrganizeGeneralDetailVO> orgListForCurrUser = userApiV2Util.getOrgListForCurrUser(
                List.of(OrganizeCategoryEnums.COMPANY, OrganizeCategoryEnums.STORE, OrganizeCategoryEnums.DEPARTMENT), null);

        if (CollUtil.isEmpty(orgListForCurrUser)) {
            return Collections.emptyList();
        }
        // 获取组织id
        return orgListForCurrUser.stream()
                .map(OrganizeGeneralDetailVO::getId).filter(vo -> dto.getOrgIds().contains(vo))
                .collect(Collectors.toList());
    }

    /**
     * 计算各项统计数据
     */
    private void calculateStatistics(FtbCultivateStatisticsDTO dto, NumberofAppSessions numberofAppSessions) {
        // 完课率 已学习/学习中+已学习
        Integer courseCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRate(dto, List.of(1));
        Integer denominatorCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRate(dto, List.of(0, 1, 2));

        ExamStatisticsVo vo = examUserService.statisticsNew(dto);
        // 考试整体总合格率
        String passRate = vo.getCurrPassRate();

        IdentifyStatisticsForNewVo identifyStatistics = applyService.getHandsOnStatistics(dto);

        // 已学习
        numberofAppSessions.setNumberOfStudents(BigDecimal.valueOf(courseCompletionRate));
        // 学习中+已学习
        numberofAppSessions.setNumberOfCourse(BigDecimal.valueOf(denominatorCompletionRate));
        // 完课率
        numberofAppSessions.setCourseCompletionRate(getCompletionRate(courseCompletionRate, denominatorCompletionRate));

        numberofAppSessions.setExamTotleRate(passRate);
        // 考试总人数
        numberofAppSessions.setTotalNumberExam(vo.getCurrExamTotleNum());
        // 考试合格人数
        numberofAppSessions.setNumberOfExam(BigDecimal.valueOf(Long.parseLong(vo.getCurrExamPassNum())));

        // 实操合格率
        numberofAppSessions.setIdentifyPassRate(identifyStatistics.getPassRate());
        // 实操合格人数
        numberofAppSessions.setNumberOfOperation(BigDecimal.valueOf(identifyStatistics.getPassNumber()));
        // 鉴定总人数
        numberofAppSessions.setTotalNumberOfAppraisals(BigDecimal.valueOf(identifyStatistics.getTotalPeople()));
    }

    @Override
    public List<NumberofAppSessions> trainingStatistics(FtbCultivateStatisticsDTO dto) {
        List<NumberofAppSessions> reultList = Collections.synchronizedList(new ArrayList<NumberofAppSessions>());
        List<String> organizeIdsAdnChildByUserId = new ArrayList<>();

        Map<String, String> orgNameMap = new HashMap<>();
        if (CollUtil.isNotEmpty(dto.getOrgIds())) {
            List<String> orgIds = dto.getOrgIds();
            if (StringUtil.isNotEmpty(dto.getOrgId())) {
                orgIds.add(dto.getOrgId());
            }
            organizeIdsAdnChildByUserId.addAll(orgIds);
            List<OrganizeGeneralDetailVO> childrenOneLevelById = userApiV2Util.batchOrganizeNextLevel(orgIds, null);
            if (CollUtil.isNotEmpty(childrenOneLevelById)) {
                organizeIdsAdnChildByUserId.addAll(childrenOneLevelById.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            }
            List<OrganizeGeneralDetailVO> orgListForCurrUser = userApiV2Util.getOrgListForCurrUser(
                    List.of(OrganizeCategoryEnums.COMPANY, OrganizeCategoryEnums.STORE, OrganizeCategoryEnums.DEPARTMENT), null);

            if (CollUtil.isEmpty(orgListForCurrUser)) {
                return reultList;
            }

            List<String> intersection = UserApiV2Util.getIntersection(organizeIdsAdnChildByUserId, orgListForCurrUser.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            if (CollUtil.isEmpty(intersection)) {
                return reultList;
            } else {
                organizeIdsAdnChildByUserId = intersection;
            }
        } else if (StringUtil.isEmpty(dto.getOrgId())) {
            List<OrganizeManagerFilterNodeVO> orgListTreeeForCurrUser = userApiV2Util.getOrgListTreeForCurrUser(
                    List.of(OrganizeCategoryEnums.COMPANY, OrganizeCategoryEnums.STORE, OrganizeCategoryEnums.DEPARTMENT));
            organizeIdsAdnChildByUserId = userApiV2Util.getTopOrgList(orgListTreeeForCurrUser);
            if (CollUtil.isEmpty(organizeIdsAdnChildByUserId)) {
                return reultList;
            }
        } else {
            List<OrganizeGeneralDetailVO> childrenOneLevelById = userApiV2Util.organizeNextLevel(dto.getOrgId(), null);
            if (CollUtil.isNotEmpty(childrenOneLevelById)) {
                organizeIdsAdnChildByUserId.addAll(childrenOneLevelById.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            }
            List<OrganizeGeneralDetailVO> orgListForCurrUser = userApiV2Util.getOrgListForCurrUser(
                    List.of(OrganizeCategoryEnums.COMPANY, OrganizeCategoryEnums.STORE, OrganizeCategoryEnums.DEPARTMENT), null);
            if (CollUtil.isEmpty(orgListForCurrUser)) {
                return reultList;
            }
            List<String> intersection = UserApiV2Util.getIntersection(organizeIdsAdnChildByUserId, orgListForCurrUser.stream().map(OrganizeGeneralDetailVO::getId).collect(Collectors.toList()));
            if (CollUtil.isEmpty(intersection)) {
                return reultList;
            } else {
                organizeIdsAdnChildByUserId = intersection;
            }

        }
        if (CollUtil.isNotEmpty(organizeIdsAdnChildByUserId)) {
            List<OrganizeGeneralDetailVO> organizeByIds = userApiV2Util.organizesByOrganizeIds(organizeIdsAdnChildByUserId, null);
            if (CollUtil.isNotEmpty(organizeByIds)) {
                orgNameMap =
                        organizeByIds.stream()
                                .collect(Collectors.toMap(OrganizeGeneralDetailVO::getId, OrganizeGeneralDetailVO::getName, (a, b) -> a));
            }
        }
        Map<String, List<UserPageListVO>> orgUserMap = new HashMap<>();
        List<UserPageListVO> allUserLists = userApiV2Util.getUserListForOrgIds(organizeIdsAdnChildByUserId, null);
        if (CollUtil.isNotEmpty(allUserLists)) {
            orgUserMap = allUserLists.stream().collect(Collectors.groupingBy(UserPageListVO::getOrganizeId));
        }

        String tenantId = UserProvider.getUser().getTenantId();
        List<OrganizeManagerNodeVO> organizeManagerNodeVOS = userApiV2Util.queryAllOrgReturnTree(null);
        Map<String, OrganizeManagerNodeVO> orgTreeMap = new HashMap<>();
        UserApiV2Util.convertToOrgMap(organizeManagerNodeVOS, orgTreeMap);
        final Map<String, List<UserPageListVO>> orgUserMap1 = orgUserMap;
        final Map<String, String> orgNameMap1 = orgNameMap;

        organizeIdsAdnChildByUserId.forEach(str -> {
            FtbCultivateStatisticsDTO newDto = BeanUtil.toBean(dto, FtbCultivateStatisticsDTO.class);

            // 查询当前组织下所有组织的信息 包含关系
            List<String> selectUserIds = new ArrayList<>();
            List<String> childrenById = new ArrayList<>();
            OrganizeManagerNodeVO organizeManagerNodeVO = orgTreeMap.get(str);
            runGetCurrAndNextLevel(childrenById, organizeManagerNodeVO);
            newDto.setOrgIds(childrenById);
            if (CollUtil.isNotEmpty(childrenById)) {

                for (String s : childrenById) {
                    List<UserPageListVO> listVOS = orgUserMap1.get(s);
                    if (CollUtil.isNotEmpty(listVOS)) {
                        selectUserIds.addAll(listVOS.stream().map(UserPageListVO::getId).collect(Collectors.toList()));
                    }
                }
                newDto.setUserIds(selectUserIds);
            }
            NumberofAppSessions numberofAppSessions = new NumberofAppSessions();
            numberofAppSessions.setOrgId(str);
            numberofAppSessions.setOrgName(orgNameMap1.get(str));
            if (CollUtil.isEmpty(newDto.getUserIds())) {
                reultList.add(numberofAppSessions);
                return;
            }
//            try {
//                TenantDataSourceUtil.switchTenant(tenantId);//静态方法切库
//            } catch (LoginException e) {
//                throw new RuntimeException(e);
//            }
            // 完课率 已学习/学习中+已学习
            newDto.setOrgIds(new ArrayList<>());
            Integer courseCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRate(newDto, List.of(1));
            Integer denominatorCompletionRate = ftbCultivateStatisticsMapper.courseCompletionRate(newDto, List.of(0, 1, 2));
            // 已学习
            numberofAppSessions.setNumberOfStudents(BigDecimal.valueOf(courseCompletionRate));
            // 学习中+已学习
            numberofAppSessions.setNumberOfCourse(BigDecimal.valueOf(denominatorCompletionRate));
            // 完课率
            numberofAppSessions.setCourseCompletionRate(getCompletionRate(courseCompletionRate, denominatorCompletionRate));
            ExamStatisticsVo vo = examUserService.statisticsNew(newDto);
            // 考试整体总合格率
            String passRate = vo.getCurrPassRate();
            numberofAppSessions.setExamTotleRate(passRate);
            // 考试总人数
            numberofAppSessions.setTotalNumberExam(vo.getCurrExamTotleNum());
            // 考试合格人数
            numberofAppSessions.setNumberOfExam(BigDecimal.valueOf(Long.parseLong(vo.getCurrExamPassNum())));
            IdentifyStatisticsForNewVo identifyStatistics = applyService.getHandsOnStatistics(newDto);
            // 实操合格率
            numberofAppSessions.setIdentifyPassRate(identifyStatistics.getPassRate());
            // 实操合格人数
            numberofAppSessions.setNumberOfOperation(BigDecimal.valueOf(identifyStatistics.getPassNumber()));
            // 鉴定总人数
            numberofAppSessions.setTotalNumberOfAppraisals(BigDecimal.valueOf(identifyStatistics.getTotalPeople()));
            reultList.add(numberofAppSessions);
        });

        return reultList;
    }

    /**
     * 获取组织tree下的所有 组织ids
     *
     * @param childrenById
     * @param organizeManagerNodeVO 节点tree
     */
    public void runGetCurrAndNextLevel(List<String> childrenById, OrganizeManagerNodeVO organizeManagerNodeVO) {
        if (organizeManagerNodeVO == null) {
            return;
        }
        childrenById.add(organizeManagerNodeVO.getId());
        List<OrganizeManagerNodeVO> children = organizeManagerNodeVO.getChildren();
        if (CollUtil.isNotEmpty(children)) {
            for (OrganizeManagerNodeVO child : children) {
                runGetCurrAndNextLevel(childrenById, child);
            }
        }
    }


    /**
     * 获取用户列表
     *
     * @param dto
     */
    private void getUserList(FtbCultivateStatisticsDTO dto) {
        List<UserPageListVO> listFeign = userApiV2Util.getUserListForOrgIds(dto.getOrgIds(), null);
        if (CollUtil.isNotEmpty(listFeign)) {
            List<String> userIds = listFeign.stream().map(UserPageListVO::getId).distinct().collect(Collectors.toList());
            dto.setUserIds(userIds);
        } else {
            log.info("课程学习统计，获取组织id:{}，所对应的人员为空", dto.getOrgId());
        }
    }

    /**
     * 计算完成率
     *
     * @param num   完成的数量
     * @param total 总数量
     * @return 完成率
     */
    private static BigDecimal getCompletionRate(Integer num, Integer total) {
        if (total == 0) {
            return BigDecimal.ZERO;
        }
        return new BigDecimal(num).divide(new BigDecimal(total), 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
    }

}
