package net.northking.cctp.dw.schedule;

import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.dw.api.service.*;
import net.northking.cctp.dw.constant.DWBaseConstant;
import net.northking.cctp.dw.constant.DWConstant;
import net.northking.cctp.dw.constant.DWError;
import net.northking.cctp.dw.db.entity.*;
import net.northking.cctp.dw.db.service.*;
import net.northking.cctp.dw.dto.BugOverallTendencyChartDto;
import net.northking.cctp.dw.enums.ProgressType;
import net.northking.cctp.dw.utils.DataDealUtil;
import net.northking.cctp.dw.utils.DateDealUtils;
import net.northking.cctp.dw.utils.ListUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.TransactionTemplate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Period;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

//@Component
public class ScheduleTask {

    private final static Logger logger = LoggerFactory.getLogger(ScheduleTask.class);

    @Autowired
    private MtTestPointApiService mtTestPointApiService;

    @Autowired
    private MtManualExecJobApiService manualExecJobApiService;

    @Autowired
    private MtCaseDesignApiService mtCaseDesignApiService;

    @Autowired
    private ChartApiService chartApiService;

    @Autowired
    private BugChartService bugChartService;

    @Autowired
    private CpProjectDetailService projectDetailService;

    @Autowired
    private MidProjectInfoService projectInfoService;

    @Autowired
    private ProgressChartPrepareService prepareService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private RedisLockRegistry redisLockRegistry;

    @Autowired
    private SynBugInfoService synBugInfoService;

    @Autowired
    private BugTemplateStatusService bugTemplateStatusService;

    @Autowired
    private BugLifeCycleChartService bugLifeCycleChartService;

    @Autowired
    private BugOverallTendencyChartService bugOverallTendencyChartService;

    @Autowired
    private BugGradeStatisticsService bugGradeStatisticsService;

    @Autowired
    private BugTendencyChartTmpService bugTendencyChartTmpService;

    @Autowired
    private BugStatusStatisticsService bugStatusStatisticsService;

    @Autowired
    private BugValidRepairRatioService bugValidRepairRatioService;

    @Autowired
    private MidUserBugGradeService midUserBugGradeService;

    @Autowired
    private BugDensityChartService bugDensityChartService;

    @Autowired
    private BugLegacyGradeService bugLegacyGradeService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private DwTestPointService dwTestPointService;

    @Autowired
    private MtManualExecJobApiService mtManualExecJobApiService;

    @Autowired
    private MidProjectInfoService midProjectInfoService;

    @Autowired
    private DwCaseDesignInfoService dwCaseDesignInfoService;

    @Autowired
    private DwManualExecJobService dwManualExecJobService;

    /**
     * 当日需求分析、用例设计、用例执行进度图数据统计
     */
    @Scheduled(fixedDelayString = "${nk.scheduled2:120000}")
    public void createChartProgress() {

        //  加锁解决集群后多次触发问题
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.CREATE_CHART_PROGRESS);
        boolean b = lock.tryLock();
        if (!b) return;
        try {
            // 查询cp_project_detail表租户id列表
            List<String> tenantIds = projectDetailService.findTenantIds();
            tenantIds.forEach(
                    tenantId -> {
                        //  测试点进度
                        List<MtTestChart> pointProgress = mtTestPointApiService.createTestPointPlanProgress(tenantId);
                        //
                        compareDateWithMax(pointProgress, chartApiService.findMaxDateGroupByProId(ProgressType.TEST_POINT.getCode()));
                        //  执行进度
                        List<MtTestChart> execJobProgress = manualExecJobApiService.createExecJobProgress(tenantId);
                        //
                        compareDateWithMax(execJobProgress, chartApiService.findMaxDateGroupByProId(ProgressType.CASE_EXEC.getCode()));
                        //  案例进度
                        List<MtTestChart> caseDesignProgress = mtCaseDesignApiService.createCaseDesignProgress(tenantId);
                        //
                        compareDateWithMax(caseDesignProgress, chartApiService.findMaxDateGroupByProId(ProgressType.CASE_DESIGN.getCode()));

                        pointProgress.addAll(execJobProgress);
                        pointProgress.addAll(caseDesignProgress);

                        //  新增测试点、用例设计、执行数据
                        if (CollectionUtils.isNotEmpty(pointProgress)) {
                            transactionTemplate.execute(s -> {
                                //  删除今天除总进度之外的数据数据
                                chartApiService.deleteTodayData(tenantId);
                                chartApiService.addBatchTestChart(pointProgress);
                                return Boolean.TRUE;
                            });

                        }
                    });
        } catch (TransactionException e) {
            throw new PlatformRuntimeException(DWError.CREATE_PROGRESS_DATA_FAILED, e);
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

    public void compareDateWithMax(List<MtTestChart> progressData, List<MtTestChart> mtProgressData) {

        Map<? extends String, List<MtTestChart>> listMap = ListUtils.groupBy(mtProgressData, MtTestChart::getProjectId);
        List<MtTestChart> tmpMtTestChartList = new ArrayList<>();
        SimpleDateFormat s = new SimpleDateFormat(DWBaseConstant.SIMPLE_DATE_FORMAT);
        progressData.forEach(p -> {
            List<MtTestChart> mtTestCharts = listMap.get(p.getProjectId());
            if (mtTestCharts != null && mtTestCharts.size() != 0) {
                if (mtTestCharts.get(0).getRecordDate().before(p.getRecordDate())) {
                    Calendar c = Calendar.getInstance();
                    Calendar c1 = Calendar.getInstance();
                    c1.setTime(mtTestCharts.get(0).getRecordDate());
                    Calendar c2 = Calendar.getInstance();
                    c2.setTime(p.getRecordDate());
                    Period p1 = Period.between(LocalDate.of(c1.get(Calendar.YEAR), c1.get(Calendar.MONTH) + 1, c1.get(Calendar.DAY_OF_MONTH)), LocalDate.of(c2.get(Calendar.YEAR), c2.get(Calendar.MONTH) + 1, c2.get(Calendar.DAY_OF_MONTH)));
                    for (int i = 1; i < p1.getDays(); i++) {
                        //为断层的日期补充数据
                        MtTestChart m = new MtTestChart();
                        c.add(Calendar.DATE, -1);
                        try {
                            m.setRecordDate(s.parse(s.format(c.getTime())));
                        } catch (ParseException e) {
                           logger.error("日期解析失败",e);
                        }
                        m.setTestType(p.getTestType());
                        m.setProjectId(p.getProjectId());
                        m.setTenantId(p.getTenantId());
                        tmpMtTestChartList.add(m);
                    }
                }
            }
        });
        progressData.addAll(tmpMtTestChartList);
    }

    /**
     * 进度数据准备
     */
    @Scheduled(fixedDelayString = "${nk.scheduled2:120000}")
    public void prepareChartProgressData() {
        //  加锁解决集群后多次触发问题
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.PREPARE_CHART_PROGRESS);
        boolean b = lock.tryLock();
        if (!b) return;
        try {
            List<MidProjectInfo> projectInfos = dwManualExecJobService.findProIdList();

            if (!projectInfos.isEmpty()) {

                Map<String, List<MidProjectInfo>> collect = projectInfos.stream().filter(midProjectInfo -> StringUtils.isNotBlank(midProjectInfo.getTenantId())).collect(Collectors.groupingBy(MidProjectInfo::getTenantId));
                Iterator<Map.Entry<String, List<MidProjectInfo>>> iterator = collect.entrySet().iterator();
                while(iterator.hasNext()) {
                    //  每20条数据发送一个队列
                    List<MidProjectInfo> value = iterator.next().getValue();
                    int count = 20;
                    Integer num = value.size();
                    for (int i = 0; i < num / count + 1; i++) {
                        if (i * count == num) {
                            break;
                        }
                        int stop = (i + 1) * count > num ? num : (i + 1) * count;
                        List<MidProjectInfo> dataList = value.subList(i * count, stop);
                        // 发送消息
                        amqpTemplate.convertAndSend(DWConstant.MQ_HANDLE_DATA_EXCHANGE, DWConstant.BugRoutingKey.PREPARE_CHART_PROGRESS, dataList);
                    }
                }
            }
        } catch (TransactionException e) {
            throw new PlatformRuntimeException(DWError.CREATE_PROGRESS_DATA_FAILED, e);
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

    /**
     * 计算当天总进度数据
     *
     * @param details
     * @param toDay
     * @param proId
     * @param info
     * @param charts
     * @return
     */
    public MtTestChart getMtTestChart(List<CpProjectDetail> details, Date toDay, String proId, MidProjectInfo info,List<MtTestChart> charts) {
        if (null==details||null==charts)
            return null;
        //  获取最小时间
        Date minStartTime = getMinStartTime(details, proId);

        //  若未设置计划时间，则不生成总进度
        if (Objects.isNull(minStartTime)) {
            return null;
        }

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(minStartTime);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        //  当天时间如果小于最小时间-1,则不生成总进度
        if (toDay.before(calendar.getTime())) {
            return null;
        }

        MtTestChart chart = new MtTestChart();
        //计算总进度图的实际进度
        Double actual=0.0;
        Integer count=0;
        for (MtTestChart mtTestChart:charts) {
            if (null == mtTestChart.getPercentActual()) {
                count++;
            }else{
                if (mtTestChart.getTestType() == 1)
                    actual = actual + mtTestChart.getPercentActual() * 0.25;
                if (mtTestChart.getTestType() == 2)
                    actual = actual + mtTestChart.getPercentActual() * 0.22;
                if (mtTestChart.getTestType() == 3)
                    actual = actual + mtTestChart.getPercentActual() * 0.53;
            }
        }
        if (count!=charts.size()){
            chart.setPercentActual(actual);
            //计算总进度图的计划进度
            int workDay = DateDealUtils.calculateWorkDay(info.getStartTime(), info.getProductionTime());
            double planPercent = 0.0;
            if (workDay != 0 && !calendar.getTime().equals(toDay)) {
                int day = DateDealUtils.calculateWorkDay(minStartTime, toDay);
                planPercent = DataDealUtil.calculateTwo(day * 100, workDay);
            }
            chart.setPercentPlan(planPercent);
        }else{
            chart.setPercentActual(null);
            chart.setPercentPlan(null);
        }
        chart.setTenantId(info.getTenantId());
        chart.setProjectId(proId);
        chart.setRecordDate(toDay);
        chart.setTestType(ProgressType.OVERALL_TEST.getCode());

        return chart;
    }

    /**
     * 组装进度图准备数据
     *
     * @param proId
     * @param tenantId
     * @param caseTotal
     * @param testTotal
     * @param execNum
     * @param validExecTotal
     * @return
     */
    public ProgressChartPrepare getProgressChartPrepare(String proId, String tenantId, int caseTotal, int testTotal, int execNum, int validExecTotal) {
        ProgressChartPrepare prepare = new ProgressChartPrepare();
        prepare.setProjectId(proId);
        prepare.setTenantId(tenantId);
        prepare.setCaseTotal(caseTotal);
        prepare.setTestPointTotal(testTotal);
        prepare.setExecSum(execNum);
        prepare.setExecTotal(validExecTotal);
        return prepare;
    }

    /**
     * 获取最小时间
     *
     * @param details
     * @param projectId
     * @return
     */
    public Date getMinStartTime(List<CpProjectDetail> details, String projectId) {
        Date minStartTime = null;
        for (CpProjectDetail projectDetail : details) {
            if (Objects.isNull(minStartTime) && Objects.nonNull(projectDetail.getStartTime()) && projectId.equals(projectDetail.getProjectId())) {
                minStartTime = projectDetail.getStartTime();
            } else if (Objects.nonNull(projectDetail.getStartTime()) && projectId.equals(projectDetail.getProjectId())) {
                if (minStartTime != null && minStartTime.compareTo(projectDetail.getStartTime()) > 0) {
                    minStartTime = projectDetail.getStartTime();
                }
            }
        }
        return minStartTime;
    }

    /**
     * 定时生成缺陷生命周期数据
     */
    @Scheduled(fixedDelayString = "${nk.scheduled1:60000}")
    public void syncBugLifeCycleNotice() {
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.SYN_BUG_LIFE_CYCLE);
        boolean b = lock.tryLock();
        try {
            if (b) {
                //每次导入数据之前先清空所有数据
                long startTime = System.currentTimeMillis();
                // 查询出所有的projectIds
                List<BugLifeCycleChart> bugLifeCycleChartList = bugLifeCycleChartService.getProjectList();
                if (!bugLifeCycleChartList.isEmpty()) {
                    // 根据租户id分组
                    Map<String, List<BugLifeCycleChart>> map = bugLifeCycleChartList.stream().filter(bugLifeCycleChart->StringUtils.isNotBlank(bugLifeCycleChart.getTenantId())).collect(Collectors.groupingBy(BugLifeCycleChart::getTenantId));
                    Iterator<Map.Entry<String, List<BugLifeCycleChart>>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, List<BugLifeCycleChart>> next = iterator.next();
                        List<BugLifeCycleChart> jobList = next.getValue();
                        // 每20个系统作为一个队列
                        int count = 20;
                        Integer num = jobList.size();
                        for (int i = 0; i < num / count + 1; i++) {
                            if (i * count == num) {
                                break;
                            }
                            int stop = (i + 1) * count > num ? num : (i + 1) * count;
                            List<BugLifeCycleChart> dataList = jobList.subList(i * count, stop);
                            // 发送消息
                            amqpTemplate.convertAndSend(DWConstant.MQ_HANDLE_DATA_EXCHANGE, DWConstant.BugRoutingKey.BUG_LIFE_CYCLE, dataList);
                        }
                    }
                }
                long endTime = System.currentTimeMillis();
                logger.info("=====syncBugLifeCycleNotice======总耗时：" + (endTime - startTime));
            }
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

    /**
     * 定时生成周报以及跨系统图表中缺陷趋势信息
     */
    @Scheduled(fixedDelayString = "${nk.scheduled2:120000}")
    public void syncBugTendencyChartNotice() {
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.SYN_BUG_OVERALL_TENDENCY_CHART);
        boolean b = lock.tryLock();
        try {
            if (b) {
                // 查询出所有的projectIds
                List<BugOverallTendencyChartDto> bugOverallTendencyChartDtoList = bugOverallTendencyChartService.getProjectList();
                if (!bugOverallTendencyChartDtoList.isEmpty()) {
                    // 根据租户id分组
                    Map<String, List<BugOverallTendencyChartDto>> map = bugOverallTendencyChartDtoList.stream().filter(bugOverallTendencyChartDto -> StringUtils.isNotBlank(bugOverallTendencyChartDto.getTenantId())).collect(Collectors.groupingBy(BugOverallTendencyChartDto::getTenantId));
                    Iterator<Map.Entry<String, List<BugOverallTendencyChartDto>>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, List<BugOverallTendencyChartDto>> next = iterator.next();
                        List<BugOverallTendencyChartDto> jobList = next.getValue();
                        //  每20条数据发送一个队列
                        int count = 20;
                        Integer num = jobList.size();
                        for (int i = 0; i < num / count + 1; i++) {
                            if (i * count == num) {
                                break;
                            }
                            int stop = (i + 1) * count > num ? num : (i + 1) * count;
                            List<BugOverallTendencyChartDto> dataList = jobList.subList(i * count, stop);
                            // 发送消息
                            amqpTemplate.convertAndSend(DWConstant.MQ_HANDLE_DATA_EXCHANGE, DWConstant.BugRoutingKey.BUG_OVERALL_TENDENCY_CHART, dataList);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.info("=========syncBugTendencyChart2Notice=======" + e.getMessage());
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

    /**
     * 定时生成缺陷严重程度数据
     */
    @Scheduled(fixedDelayString = "${nk.scheduled1:60000}")
    public void syncBugGradeNotice() {
        //  定时任务加锁解决集群后多次触发问题
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.SYN_BUG_GRADE);
        boolean b = lock.tryLock();
        try {
            if (b) {
                List<SynBugInfo> synBugInfoList = synBugInfoService.findProIdList();
                if (!synBugInfoList.isEmpty()) {
                    //  每20条数据发送一个队列
                    Map<String, List<SynBugInfo>> collect = synBugInfoList.stream().filter(synBugInfo -> StringUtils.isNotBlank(synBugInfo.getTenantId())).collect(Collectors.groupingBy(SynBugInfo::getTenantId));
                    Iterator<Map.Entry<String, List<SynBugInfo>>> iterator = collect.entrySet().iterator();
                    while (iterator.hasNext()){
                        Map.Entry<String, List<SynBugInfo>> next = iterator.next();
                        List<SynBugInfo> value = next.getValue();
                        int count = 20;
                        Integer num = value.size();
                        for (int i = 0; i < num / count + 1; i++) {
                            if (i * count == num) {
                                break;
                            }
                            int stop = (i + 1) * count > num ? num : (i + 1) * count;
                            List<SynBugInfo> dataList = value.subList(i * count, stop);
                            // 发送消息
                            amqpTemplate.convertAndSend(DWConstant.MQ_HANDLE_DATA_EXCHANGE, DWConstant.BugRoutingKey.SYN_BUG_GRADE, dataList);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("定时生成缺陷严重程度数据发送失败",e);
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

    /**
     * 定时生成缺陷密度数据
     */
    @Scheduled(fixedDelayString = "${nk.scheduled2:120000}")
    public void bugDensityChart2() {
        //  加锁解决集群后多次触发问题
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.BUG_DENSITY_CHART);
        boolean b = lock.tryLock();
        try {
            if (b) {
                long startTime = System.currentTimeMillis();
                // 查询出所有的projectIds
                MidProjectInfo projectInfo = new MidProjectInfo();
                projectInfo.setDeleted(false);
                List<MidProjectInfo> projectInfos = projectInfoService.query(projectInfo);
                Integer num = projectInfos.size();
                logger.info("================总系统数量:" + num);
                if (!projectInfos.isEmpty()) {
                    //  每20条数据发送一个队列
                    Map<String, List<MidProjectInfo>> map = projectInfos.stream().filter(midProjectInfo -> StringUtils.isNotBlank(midProjectInfo.getTenantId())).collect(Collectors.groupingBy(MidProjectInfo::getTenantId));
                    Iterator<Map.Entry<String, List<MidProjectInfo>>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, List<MidProjectInfo>> next = iterator.next();
                        List<MidProjectInfo> jobList = next.getValue();
                        num=jobList.size();
                        int count = 20;
                        for (int i = 0; i < num / count + 1; i++) {
                            if (i * count == num) {
                                break;
                            }
                            int stop = (i + 1) * count > num ? num : (i + 1) * count;
                            List<MidProjectInfo> dataList = jobList.subList(i * count, stop);
                            // 发送消息
                            amqpTemplate.convertAndSend(DWConstant.MQ_HANDLE_DATA_EXCHANGE, DWConstant.BugRoutingKey.BUG_DENSITY_CHART, dataList);
                        }
                    }
                }
                long endTime = System.currentTimeMillis();
                logger.info("=====bugDensityChart2======总耗时：" + (endTime - startTime));
            }
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

    /**
     * 定时生成缺陷遗留数据
     */
    @Scheduled(fixedDelayString = "${nk.scheduled2:120000}")
    public void bugLegacyGrade2() {
        //  加锁解决集群后多次触发问题
        Lock lock = redisLockRegistry.obtain(DWBaseConstant.BUG_LEGACY_GRADE);
        boolean b = lock.tryLock();
        try {
            if (b) {
                long startTime = System.currentTimeMillis();
                // 查询出所有的projectIds
                List<BugLegacyGrade> bugLegacyGradeList = bugLegacyGradeService.getProjectList();
                if (!bugLegacyGradeList.isEmpty()) {
                    // 根据租户id分组
                    Map<String, List<BugLegacyGrade>> map = bugLegacyGradeList.stream().filter(bugLegacyGrade -> StringUtils.isNotBlank(bugLegacyGrade.getTenantId())).collect(Collectors.groupingBy(BugLegacyGrade::getTenantId));
                    Iterator<Map.Entry<String, List<BugLegacyGrade>>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, List<BugLegacyGrade>> next = iterator.next();
                        List<BugLegacyGrade> jobList = next.getValue();
                        //  每20条数据发送一个队列
                        int count = 20;
                        Integer num = jobList.size();
                        for (int i = 0; i < num / count + 1; i++) {
                            if (i * count == num) {
                                break;
                            }
                            int stop = (i + 1) * count > num ? num : (i + 1) * count;
                            List<BugLegacyGrade> dataList = jobList.subList(i * count, stop);
                            // 发送消息
                            amqpTemplate.convertAndSend(DWConstant.MQ_HANDLE_DATA_EXCHANGE, DWConstant.BugRoutingKey.BUG_LEGACY_GRADE, dataList);
                        }
                    }
                }
                long endTime = System.currentTimeMillis();
                logger.info("=====bugLegacyGrade2======总耗时：" + (endTime - startTime));
            }
        } finally {
            if (b) {
                lock.unlock();
            }
        }
    }

}
