package net.northking.cctp.dw.api.service;

import net.northking.cctp.common.cache.EntityNameCache;
import net.northking.cctp.common.cache.EntityNameCatalog;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.common.security.authentication.NKSecurityContext;
import net.northking.cctp.dw.constant.DWError;
import net.northking.cctp.dw.db.entity.*;
import net.northking.cctp.dw.db.service.MidProjectInfoService;
import net.northking.cctp.dw.db.service.MtTestChartService;
import net.northking.cctp.dw.db.service.ProgressChartPrepareService;
import net.northking.cctp.dw.dto.ChartProgressQueryDto;
import net.northking.cctp.dw.dto.MtTestChartDto;
import net.northking.cctp.dw.dto.ProjectDataVo;
import net.northking.cctp.dw.enums.ProgressType;
import net.northking.cctp.dw.feign.ProjectsFeignClient;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: puchao.ma
 * @date: 2021/12/15 16:16
 */
@Service
public class ChartApiServiceImpl implements ChartApiService {

    private final static Logger logger = LoggerFactory.getLogger(ChartApiServiceImpl.class);
    @Autowired
    private MtTestChartService mtTestChartService;

    @Autowired
    private CpProjectDetailApiService projectDetailApiService;

    @Autowired
    private MidProjectInfoService projectInfoService;

    @Autowired
    private ProgressChartPrepareService prepareService;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private EntityNameCache entityNameCache;

    @Autowired
    private ProjectsFeignClient projectsFeignClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBatchTestChart(List<MtTestChart> pointProgress) {
        mtTestChartService.insertByBatch(pointProgress);
    }

    /**
     * 根据系统id和类型查询进度数据
     */
    @Override
    public List<MtTestChartDto> queryChartProgress(ChartProgressQueryDto queryDto) {
        List<MtTestChartDto> chartDtos = null;
        try {
            chartDtos = mtTestChartService.queryChartProgress(queryDto);
        } catch (Exception e) {
            throw new PlatformRuntimeException(DWError.QUERY_CHART_PROGRESS_FAILED, e);
        }
        return chartDtos;
    }

    /**
     * 总体测试报告
     *
     * @return
     */
    @Override
    @Transactional
    public List<MtTestChart> createOverallTestReportProgress() {
        return mtTestChartService.createOverallTestReportProgress();
    }

    @Override
    @Transactional(isolation = Isolation.SERIALIZABLE, rollbackFor = Exception.class)
    public void deleteTodayData(String tenantId) {
        mtTestChartService.deleteProgress(tenantId);
    }

    @Override
    public void deleteByPrimaryKeys(List<Object> chartIds) {
        mtTestChartService.deleteByPrimaryKeys(chartIds);
    }

    @Override
    public List<MtTestChart> queryToday(List<MidProjectInfo> midProjectInfos) {
        return mtTestChartService.queryToday(midProjectInfos);
    }

    @Override
    public Integer queryTodayDeleted(List<MidProjectInfo> dataList) {
        return mtTestChartService.queryTodayDeleted(dataList);
    }

    @Override
    public List<ProjectDataVo> getProjectIds(String tenantId) {
        List<ProjectDataVo> projectIds = mtTestChartService.getProjectIds(tenantId);
        if (null!=projectIds&&projectIds.size()!=0){
            List<String> stringList = projectsFeignClient.filtersProjectIds(projectIds.stream().map(ProjectDataVo::getProjectId).collect(Collectors.toList()));
            if (null==stringList||stringList.size()==0)return new ArrayList<>();
            Map<String, List<ProjectDataVo>> collect = projectIds.stream().collect(Collectors.groupingBy(ProjectDataVo::getProjectId));
            List<ProjectDataVo> results=new ArrayList<>();
            for (String projectId:stringList){
                List<ProjectDataVo> projectDataVos = collect.get(projectId);
                ProjectDataVo projectDataVo = projectDataVos.get(0);
                projectDataVo.setProjectName(entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM,projectDataVo.getProjectId()));
                results.add(projectDataVo);
            }
            return results;
        }
        else return new ArrayList<>();
    }

    @Override
    public List<String> getNoDeletedProjectIds(String tenantId) {
        return projectsFeignClient.queryProjectIds(tenantId);
    }

    /**
     * 进度图数据处理
     *
     * @param projectId
     * @param planAmount
     * @param startTime
     * @param endTime
     * @param testType
     */
    @Override
    @Transactional
    public void progressDataDeal(String projectId, Integer planAmount, Date startTime, Date endTime, Integer testType) {
        List<MtTestChart> chartInsertList = new ArrayList<>();
        int workDay = DateDealUtils.calculateWorkDay(startTime, endTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startTime);
        calendar.add(Calendar.DAY_OF_MONTH, -1);
        startTime = calendar.getTime();

        //  查询每天的进度数据
        ProgressChartPrepare prepare = new ProgressChartPrepare();
        prepare.setProjectId(projectId);
        List<ProgressChartPrepare> prepareList = prepareService.query(prepare);
        Map<? extends Date, List<ProgressChartPrepare>> preMap = ListUtils.groupBy(prepareList, ProgressChartPrepare::getCreatedTime);

        Date date = new Date();
        int i = 0;

        while (!startTime.after(date)) {
            MtTestChart chart = new MtTestChart();
            chart.setTotalPlan(planAmount);
            double value = 0;
            if (workDay != 0) {
                value = DataDealUtil.calculateTwo(100 * i, workDay);
            }

            //  若无数据则为0
            chart.setTotalActual(0);
            chart.setPercentActual(0.0);

            //  计算每天的实际进度
            if (!org.springframework.util.CollectionUtils.isEmpty(preMap) && preMap.containsKey(startTime)) {
                List<ProgressChartPrepare> prepares = preMap.get(startTime);
                ProgressChartPrepare chartPrepare = prepares.get(0);
                calculatePercentActual(chartPrepare, planAmount, testType, chart);
            }

            chart.setProjectId(projectId);
            chart.setTenantId(NKSecurityContext.getTenantId());
            chart.setTestType(testType);
            chart.setPercentPlan(value);
            chart.setRecordDate(startTime);
            chartInsertList.add(chart);

            //  非工作日不计算计划进度
            calendar.add(Calendar.DAY_OF_MONTH, 1);
            int week = calendar.get(Calendar.DAY_OF_WEEK);
            if (week != Calendar.SATURDAY && week != Calendar.SUNDAY) {
                i = i < workDay ? i + 1 : workDay;
            }

            startTime = calendar.getTime();
        }

        if (CollectionUtils.isNotEmpty(chartInsertList)) {
            //  修改计划时间则删除旧数据，数据全部重新生成
            MtTestChart mtc = new MtTestChart();
            mtc.setTestType(testType);
            mtc.setProjectId(projectId);
            mtc.setTenantId(NKSecurityContext.getTenantId());
            //  处理事务
            transactionTemplate.execute((s) -> {
                mtTestChartService.deleteByExample(mtc);
                mtTestChartService.insertByBatch(chartInsertList);
                return Boolean.TRUE;
            });

        }
    }

    /**
     * 修改总进度数据
     *
     * @param projectId
     */
    @Override
    @Transactional
    public void progressDataDeal(String projectId) {
        List<MtTestChart> chartInsertList = new ArrayList<>();

        //  修改计划时间则删除旧数据，数据全部重新生成
        MtTestChart mtc = new MtTestChart();
        mtc.setTestType(4);
        mtc.setProjectId(projectId);
        mtTestChartService.deleteByExample(mtc);

        MidProjectInfo info = new MidProjectInfo();
        info.setProjectId(projectId);
        List<MidProjectInfo> infos = projectInfoService.query(info);
        MidProjectInfo projectInfo = infos.get(0);
        Date startTime = projectInfo.getStartTime();
        Date endTime = projectInfo.getProductionTime();

        //  查询每天的进度数据
        ProgressChartPrepare prepare = new ProgressChartPrepare();
        prepare.setProjectId(projectId);
        List<ProgressChartPrepare> prepareList = prepareService.query(prepare);
        Map<? extends Date, List<ProgressChartPrepare>> preMap = ListUtils.groupBy(prepareList, ProgressChartPrepare::getCreatedTime);

        //  查询计划数
        CpProjectDetail detail = new CpProjectDetail();
        detail.setProjectId(projectId);
        List<CpProjectDetail> details = projectDetailApiService.query(detail);
        Map<? extends Integer, List<CpProjectDetail>> detailMap = ListUtils.groupBy(details, CpProjectDetail::getDetailType);

        //  计算最小时间
        Date minStartTime = null;
        for (CpProjectDetail projectDetail : details) {
            if (Objects.isNull(minStartTime) && Objects.nonNull(projectDetail.getStartTime())) {
                minStartTime = projectDetail.getStartTime();
            } else if (Objects.nonNull(projectDetail.getStartTime())) {
                if (minStartTime.compareTo(projectDetail.getStartTime()) > 0) {
                    minStartTime = projectDetail.getStartTime();
                }
            }
        }

        if (Objects.nonNull(minStartTime) && !minStartTime.after(new Date())) {
            int workDay = DateDealUtils.calculateWorkDay(startTime, endTime);
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(minStartTime);
            calendar.add(Calendar.DAY_OF_MONTH, -1);
            startTime = calendar.getTime();

            int i = 0;
            Date date = new Date();
            while (startTime.compareTo(date) <= 0) {
                MtTestChart chart = new MtTestChart();
                chart.setTenantId(NKSecurityContext.getTenantId());
                chart.setProjectId(projectId);
                chart.setTestType(4);
                double v = 0;
                if (workDay != 0) v = DataDealUtil.calculateTwo(100 * i, workDay);
                chart.setPercentPlan(v);
                chart.setRecordDate(startTime);

                double actual = 0.0;
                if (!preMap.isEmpty() && preMap.containsKey(startTime)) {
                    ProgressChartPrepare cp = preMap.get(startTime).get(0);
                    double cd = 0.0;
                    List<CpProjectDetail> casePlan = detailMap.get(ProgressType.CASE_DESIGN.getCode());
                    if (CollectionUtils.isNotEmpty(casePlan) && Objects.nonNull(casePlan.get(0).getPlanAmount())) {
                        cd = DataDealUtil.calculateTwo(cp.getCaseTotal() * 100, detailMap.get(ProgressType.CASE_DESIGN.getCode()).get(0).getPlanAmount());
                    }
                    double tp = 0.0;
                    List<CpProjectDetail> testPlan = detailMap.get(ProgressType.TEST_POINT.getCode());
                    if (CollectionUtils.isNotEmpty(testPlan) && Objects.nonNull(testPlan.get(0).getPlanAmount())) {
                        tp = DataDealUtil.calculateTwo(cp.getTestPointTotal() * 100, detailMap.get(ProgressType.TEST_POINT.getCode()).get(0).getPlanAmount());
                    }
                    double ce = 0.0;
                    if (cp.getExecTotal() > 0) {
                        ce = DataDealUtil.calculateTwo(cp.getExecSum() * 100, cp.getExecTotal());
                    }

                    actual = cd * 0.25 + tp * 0.22 + ce * 0.53;
                }

                chart.setPercentActual(actual);
                chartInsertList.add(chart);

                //  非工作日不计算计划进度
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                int week = calendar.get(Calendar.DAY_OF_WEEK);
                if (week != Calendar.SATURDAY && week != Calendar.SUNDAY) {
                    i = i < workDay ? i + 1 : workDay;
                }
                startTime = calendar.getTime();
            }
            mtTestChartService.insertByBatch(chartInsertList);
        }
    }

    /**
     * 若未设置计划数或者时间，则删除数据
     *
     * @param projectId
     * @param detailType
     */
    @Override
    public void deleteByProjectIdAndDetailType(String projectId, Integer detailType) {
        MtTestChart chart = new MtTestChart();
        chart.setProjectId(projectId);
        chart.setTestType(detailType);
        mtTestChartService.deleteByExample(chart);
    }

    @Override
    public List<MtTestChart> findMaxDateGroupByProId(Integer testType) {
        return mtTestChartService.findMaxDateGroupByProId(testType);
    }



    /**
     * 计算每天的实际进度
     *
     * @param chartPrepare
     * @return
     */
    private void calculatePercentActual(ProgressChartPrepare chartPrepare, Integer planAmount, Integer testType, MtTestChart chart) {
        double actual = 0.0;
        switch (testType) {
            case 1:
                actual = DataDealUtil.calculateTwo(chartPrepare.getCaseTotal() * 100, planAmount);
                chart.setTotalActual(chartPrepare.getCaseTotal());
                break;
            case 2:
                actual = DataDealUtil.calculateTwo(chartPrepare.getTestPointTotal() * 100, planAmount);
                chart.setTotalActual(chartPrepare.getTestPointTotal());
                break;
            case 3:
                actual = DataDealUtil.calculateTwo(chartPrepare.getExecTotal() * 100, planAmount);
                chart.setTotalActual(chartPrepare.getExecTotal());
                break;
            default:
        }
        chart.setPercentActual(actual);
    }
}
