package com.testor.module.train.project.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.testor.biz.sys.org.model.domain.SysOrg;
import com.testor.common.core.utils.StringUtils;
import com.testor.module.sys.model.domian.NewSysOrg;
import com.testor.module.sys.service.NewSysOrgService;
import com.testor.module.train.myManagement.model.domain.TTrainMyManagement;
import com.testor.module.train.project.dao.TTrainProjectDao;
import com.testor.module.train.project.model.domain.TTrainProject;
import com.testor.module.train.project.model.dto.TTrainProjectParam;
import com.testor.module.train.project.model.enums.ChartTypeEnum;
import com.testor.module.train.project.model.enums.TrainTypeEnum;
import com.testor.module.train.project.model.enums.VisitTypeEnum;
import com.testor.module.train.project.model.stat.ProjectStatTotalVo;
import com.testor.module.train.project.service.TTrainProjectService;
import com.testor.module.train.project.service.TrainProjectStatisticsAllService;
import com.tongtech.tfw.backend.common.context.ContextUtils;
import com.tongtech.tfw.backend.common.models.supers.SuperModel;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author caq
 * @date 2024/9/5
 * @description TODO
 */
@Service
public class TrainProjectStatisticsAllServiceImpl implements TrainProjectStatisticsAllService {
    @Autowired
    private NewSysOrgService newSysOrgService;
    @Autowired
    private TTrainProjectService tTrainProjectService;
    @Autowired
    private TTrainProjectDao tTrainProjectDao;

    @Override
    public ProjectStatTotalVo findProjectNumTotal(String orgId, String startTime, String endTime, String projectId) {

        ProjectStatTotalVo statTotalVo = new ProjectStatTotalVo();
        List<String> orgIdList = findOrgIdList(orgId);

        //培训计划数量
        Integer projectCount = findProjectCount(orgId, startTime, endTime);
        statTotalVo.setProjectTotal(String.valueOf(projectCount));
        // 培训时长
        //String trainTimeSumByOrgId = tTrainProjectDao.findTrainTimeSumByOrgId(orgIdList, startTime, endTime);
        String trainTimeSumByOrgId = safeFindTrainTimeSumByOrgId(orgIdList, startTime, endTime);
        if (StringUtils.isNotBlank(trainTimeSumByOrgId)) {
            statTotalVo.setProjectTotalTime(trainTimeSumByOrgId);
        }
        //  应学人数 完成人数 和 完成率
        findFinishPersonNum(orgIdList, startTime, endTime, statTotalVo, projectId);
        return statTotalVo;
    }

    @Override
    public List<ProjectStatTotalVo> findProjectNumByOrgOrVisitType(String orgId, String startTime, String endTime, String type) {

        if (StringUtils.isNotBlank(type) && ChartTypeEnum.ORG.getValue().equals(type)) {
            List<ProjectStatTotalVo>  voList = new ArrayList<>();
            List<NewSysOrg> sysOrgList = findChildOrgListByParentId(orgId);
            if (CollectionUtils.isEmpty(sysOrgList)) {
                return voList;
            }
            for (NewSysOrg sysOrg : sysOrgList) {
                List<String> orgIdList = findOrgIdList(sysOrg.getOrgId());
                String projectNum = tTrainProjectDao.findProjectNumByOrgId(orgIdList, startTime, endTime);
                if (StringUtils.isNotBlank(projectNum) && !"0".equals(projectNum)) {
                    ProjectStatTotalVo projectStatTotalVo = new ProjectStatTotalVo();
                    projectStatTotalVo.setFanChartKey(sysOrg.getOrgName());
                    projectStatTotalVo.setFanChartValue(projectNum);
                    projectStatTotalVo.setOrgId(sysOrg.getOrgId());
                    voList.add(projectStatTotalVo);
                }
            }
            return voList;
        }

        if (StringUtils.isNotBlank(type) && ChartTypeEnum.ROLE.getValue().equals(type)) {
            if (StringUtils.isBlank(orgId)) {
                orgId = ContextUtils.getLoginUser().getOrgId();
            }
            List<String> orgIdList = findOrgIdList(orgId);

            List<ProjectStatTotalVo> projectStatTotalVoList = tTrainProjectDao.findProjectNumByOrgOrVisitType(orgIdList, startTime,
                    endTime, ChartTypeEnum.ROLE.getValue());
            projectStatTotalVoList.forEach(item -> {
                String fanChartKey = item.getFanChartKey();
                if (StringUtils.isNotBlank(fanChartKey)) {
                    String name = VisitTypeEnum.getName(fanChartKey);
                    item.setFanChartKey(name);
                }
            });
            return projectStatTotalVoList;
        }
        return null;
    }

    @Override
    public List<ProjectStatTotalVo> findPersonNumByOrgOrVisitType(String orgId, String startTime, String endTime, String type) {
        if (StringUtils.isNotBlank(type) && ChartTypeEnum.ORG.getValue().equals(type)) {
            List<ProjectStatTotalVo>  voList = new ArrayList<>();
            List<NewSysOrg> sysOrgList = findChildOrgListByParentId(orgId);
            if (CollectionUtils.isEmpty(sysOrgList)) {
                return voList;
            }
            for (NewSysOrg sysOrg : sysOrgList) {
                List<String> orgIdList = findOrgIdList(sysOrg.getOrgId());
                String projectNum = tTrainProjectDao.findPersonNumByOrgOrgId(orgIdList, startTime, endTime);
                if (StringUtils.isNotBlank(projectNum) && !"0".equals(projectNum)) {
                    ProjectStatTotalVo projectStatTotalVo = new ProjectStatTotalVo();
                    projectStatTotalVo.setFanChartKey(sysOrg.getOrgName());
                    projectStatTotalVo.setFanChartValue(projectNum);
                    projectStatTotalVo.setOrgId(sysOrg.getOrgId());
                    voList.add(projectStatTotalVo);
                }
            }
            return voList;

        }


        if (StringUtils.isNotBlank(type) && ChartTypeEnum.ROLE.getValue().equals(type)) {
            if (StringUtils.isBlank(orgId)) {
                orgId = ContextUtils.getLoginUser().getOrgId();
            }
            List<String> orgIdList = findOrgIdList(orgId);
            List<ProjectStatTotalVo> projectStatTotalVoList = tTrainProjectDao.findPersonNumByOrgOrVisitType(orgIdList, startTime,
                    endTime, ChartTypeEnum.ROLE.getValue());
            projectStatTotalVoList.forEach(item -> {
                String fanChartKey = item.getFanChartKey();
                if (StringUtils.isNotBlank(fanChartKey)) {
                    String name = VisitTypeEnum.getName(fanChartKey);
                    item.setFanChartKey(name);
                }
            });
            return projectStatTotalVoList;
        }
        return null;
    }

    @Override
    public List<ProjectStatTotalVo> findTrainTimeByOrgOrVisitType(String orgId, String startTime, String endTime, String type) {
        List<ProjectStatTotalVo> voList = new ArrayList<>();

        if (StringUtils.isNotBlank(type) && ChartTypeEnum.ORG.getValue().equals(type)) {

            List<NewSysOrg> sysOrgList = findChildOrgListByParentId(orgId);
            if (CollectionUtils.isEmpty(sysOrgList)) {
                return voList;
            }
            for (NewSysOrg sysOrg : sysOrgList) {
                List<String> orgIdList = findOrgIdList(sysOrg.getOrgId());
                //String projectNum = tTrainProjectDao.findTrainTimeSumByOrgId(orgIdList, startTime, endTime);
                String projectNum = safeFindTrainTimeSumByOrgId(orgIdList, startTime, endTime);
                if (StringUtils.isNotBlank(projectNum) && !"0".equals(projectNum)) {
                    ProjectStatTotalVo projectStatTotalVo = new ProjectStatTotalVo();
                    projectStatTotalVo.setFanChartKey(sysOrg.getOrgName());
                    projectStatTotalVo.setFanChartValue(projectNum);
                    projectStatTotalVo.setOrgId(sysOrg.getOrgId());
                    voList.add(projectStatTotalVo);
                }
            }
        }
        if (StringUtils.isNotBlank(type) && ChartTypeEnum.ROLE.getValue().equals(type)) {
            if (StringUtils.isBlank(orgId)) {
                orgId = ContextUtils.getLoginUser().getOrgId();
            }
            List<String> orgIdList = findOrgIdList(orgId);
            voList = tTrainProjectDao.findTrainTimeByOrgOrVisitType(orgIdList, startTime,
                    endTime, ChartTypeEnum.ROLE.getValue());
            voList.forEach(item -> {
                String fanChartKey = item.getFanChartKey();
                if (StringUtils.isNotBlank(fanChartKey)) {
                    String name = VisitTypeEnum.getName(fanChartKey);
                    item.setFanChartKey(name);
                }
            });

        }

        String trainTimeTotal = tTrainProjectDao.findTrainTimeTotal(startTime, endTime);
        if (StringUtils.isBlank(trainTimeTotal)) {
            trainTimeTotal = "1";
        }
        List<ProjectStatTotalVo> sortList = voList.stream()
                .sorted(Comparator.comparingInt(item -> Integer.parseInt(item.getFanChartValue()))).collect(Collectors.toList());
        Collections.reverse(sortList);

        AtomicInteger sort = new AtomicInteger(1);
        String finalTrainTimeTotal = trainTimeTotal;
        sortList.forEach(item -> {
            //String ratio = getRatio(Integer.valueOf(item.getFanChartValue()), Integer.valueOf(finalTrainTimeTotal));
            String ratio = getRatio(
                    Double.parseDouble(item.getFanChartValue()),
                    Double.parseDouble(finalTrainTimeTotal)
            );
            item.setFanChartRatio(ratio);
            item.setFanChartSort(sort.getAndIncrement());
        });

        return sortList;
    }

    /**
     * 安全执行大列表的 IN 查询，自动分批执行，返回累加结果
     *
     * @param orgIdList 机构 ID 列表
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 累加后的总结果（String 类型，兼容原 DAO 方法）
     */
    public String safeFindTrainTimeSumByOrgId(List<String> orgIdList, String startTime, String endTime) {
        if (CollectionUtils.isEmpty(orgIdList)) {
            return "0";
        }

        int batchSize = 500; // Kingbase/Oracle 等数据库单次 IN 最大限制
        int total = 0;

        for (int i = 0; i < orgIdList.size(); i += batchSize) {
            List<String> subList = orgIdList.subList(i, Math.min(i + batchSize, orgIdList.size()));
            try {
                String subResult = tTrainProjectDao.findTrainTimeSumByOrgId(subList, startTime, endTime);
                if (StringUtils.isNotBlank(subResult)) {
                    total += Integer.parseInt(subResult);
                }
            } catch (Exception e) {
            }
        }

        return String.valueOf(total);
    }


    @Override
    public ProjectStatTotalVo findTrainEvaluateStat(String orgId, String startTime, String endTime, String projectId) {

        List<String> orgIdList = findOrgIdList(orgId);

        ProjectStatTotalVo gradeStat = tTrainProjectDao.findGradeStat(orgIdList, startTime, endTime, projectId);
        String gradeScoreTotal = gradeStat.getGradeScoreTotal();
        if (StringUtils.isBlank(gradeScoreTotal)) {
            return gradeStat;
        }
        int total = new BigDecimal(gradeScoreTotal).intValue();
        int personCount = Integer.parseInt(gradeStat.getGradePersonCount());
        int avg = (int) Math.round((double) total / personCount);
        gradeStat.setGradeScoreAvg(String.valueOf(avg));
        return gradeStat;
    }

    @Override
    public List<ProjectStatTotalVo> findTrainTypeStat(String orgId, String startTime, String endTime) {

        List<String> orgIdList = findOrgIdList(orgId);
        List<ProjectStatTotalVo> trainTypeStat = tTrainProjectDao.findTrainTypeStat(orgIdList, startTime, endTime);
        if (CollectionUtils.isEmpty(trainTypeStat)) {
            return trainTypeStat;
        }
        int total = trainTypeStat.stream().map(ProjectStatTotalVo::getFanChartValue).mapToInt(Integer::parseInt).sum();
        trainTypeStat.forEach(item -> {
            String fanChartKey = item.getFanChartKey();
            if (StringUtils.isNotBlank(fanChartKey)) {
                String name = TrainTypeEnum.getName(fanChartKey);
                item.setFanChartKey(name);
            }
            //String ratio = getRatio(Integer.valueOf(item.getFanChartValue()), total);
            String ratio = getRatio(Double.valueOf(item.getFanChartValue()), Double.valueOf(total));
            item.setFanChartRatio(ratio);
            item.setFanChartTotal(String.valueOf(total));
        });
        return trainTypeStat;
    }


    private void findFinishPersonNum(List<String> orgIdList, String startTime, String endTime, ProjectStatTotalVo statTotalVo, String projectId) {
        //获取培训课程的数量
        int pageNumber = 1;
        int pageSize = 100;
        long total = 0L;
        AtomicInteger projectPersonCompleted = new AtomicInteger();
        while (true) {
            Page<TTrainProjectParam> resultPage = new Page<>(pageNumber, pageSize);
            IPage<TTrainProjectParam> page = tTrainProjectDao.findProjectPersonList(resultPage, orgIdList, startTime, endTime, projectId);
            if (page == null || CollectionUtils.isEmpty(page.getRecords())) {
                break;
            }
            total = page.getTotal();
            page.getRecords().parallelStream().forEach(item -> {
                String personId = item.getPersonId();
                String myManagementId = item.getMyManagementId();
                String courseId = item.getCourseId();
                TTrainMyManagement record = new TTrainMyManagement();
                record.setId(myManagementId);
                record.setVisitStartTime(item.getVisitStartTime());
                record.setPersonId(personId);
                record.setVisitEndTime(item.getVisitEndTime());
                record.setTabStatus(item.getTabStatus());
                tTrainProjectService.updateStatus(record, courseId);
                if ("3".equals(record.getCurrentStatus())) {
                    projectPersonCompleted.getAndIncrement();
                }
            });
            pageNumber++;
        }

        statTotalVo.setProjectPersonTotal(String.valueOf(total));
        statTotalVo.setProjectPersonCompleted(projectPersonCompleted.toString());
        // 完成率
        int projectPersonTotal = Integer.parseInt(String.valueOf(total));
        //String chapterProgress = getRatio(projectPersonCompleted.get(), projectPersonTotal);
        String chapterProgress = getRatio(Double.valueOf(projectPersonCompleted.get()), Double.valueOf(projectPersonTotal));

        statTotalVo.setProjectPersonCompletedRatio(chapterProgress);
    }

    /**
     * 查询当前机构及下级机构的计划数量
     *
     * @param orgId
     * @return
     */
    private Integer findProjectCount(String orgId, String startTime, String endTime) {
        if (StringUtils.isAnyBlank(orgId, startTime, endTime)) {
            return 0;
        }
        List<String> orgIdList = findOrgIdList(orgId);
        String projectNum = tTrainProjectDao.findProjectNumByOrgId(orgIdList, startTime, endTime);
        if (StringUtils.isBlank(projectNum)) {
            return 0;
        }
        return Integer.parseInt(projectNum);
    }

    /**
     * 查询当前机构及下级机构的所有id集合
     *
     * @param orgId
     * @return
     */
    private List<String> findOrgIdList(String orgId) {
        List<NewSysOrg> orgList = newSysOrgService.getChildrenById(orgId);
        return orgList.stream().map(NewSysOrg::getOrgId).collect(Collectors.toList());
    }


    /**
     * 查询当前机构的下级机构
     *
     * @param orgId
     * @return
     */
    private List<NewSysOrg> findChildOrgListByParentId(String orgId) {
        if (StringUtils.isBlank(orgId)) {
            orgId = ContextUtils.getLoginUser().getOrgId();
            NewSysOrg byId = newSysOrgService.getById(orgId);
            List<NewSysOrg> list = new ArrayList<>();
            list.add(byId);
            return list;
        }
        List<NewSysOrg> list = newSysOrgService.lambdaQuery().eq(SysOrg::getParentId, orgId).eq(SysOrg::getIsDept,"0")
                .eq(SuperModel::getStatus, "0").list();
        if (CollectionUtils.isEmpty(list)) {
            NewSysOrg byId = newSysOrgService.getById(orgId);
            list.add(byId);
        }
        return list;
    }
//    /**
//     * 查询当前机构及下级机构的所有id集合
//     *
//     * @param orgId
//     * @return
//     */
//    private List<String> findAllChildOrgIdList(String orgId) {
//        List<String> collect = newSysOrgService.list(new LambdaQueryWrapper<NewSysOrg>()
//                .like(NewSysOrg::getParentIds, orgId).eq(SysOrg::getIsDept,"0")).stream().map(SysOrg::getOrgId).collect(Collectors.toList());
//        collect.add(orgId);
//        return collect;
//    }




    /**
     * 计算完成率
     *
     * @param dividend 被除数
     * @param divisor  除数
     * @return
     */
    /*public String getRatio(Integer dividend, Integer divisor) {
        int percentage = (int) Math.round((double) dividend / divisor * 100);
        return percentage + "%";
    }*/

    public String getRatio(Double dividend, Double divisor) {
        int percentage = (int) Math.round(dividend / divisor * 100);
        return percentage + "%";
    }


}



