package com.ningdatech.pmapi.dashboard.manage;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.dashboard.constant.ChartTypeEnum;
import com.ningdatech.pmapi.dashboard.helper.DashboardChartAssembler;
import com.ningdatech.pmapi.dashboard.helper.DashboardHelper;
import com.ningdatech.pmapi.dashboard.model.basic.AnalysisChart;
import com.ningdatech.pmapi.dashboard.model.basic.CompanyProjectCntBO;
import com.ningdatech.pmapi.dashboard.model.basic.ProjectATIISBO;
import com.ningdatech.pmapi.dashboard.model.po.QueryYearPO;
import com.ningdatech.pmapi.dashboard.model.vo.DashboardInvestmentSummaryVO;
import com.ningdatech.pmapi.dashboard.model.vo.DashboardProjectCntSummaryVO;
import com.ningdatech.pmapi.dashboard.model.vo.DashboardProjectSummaryVO;
import com.ningdatech.pmapi.projectdeclared.model.entity.Purchase;
import com.ningdatech.pmapi.projectdeclared.service.IPurchaseService;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectDelayApply;
import com.ningdatech.pmapi.projectlib.service.INdProjectDelayApplyService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

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

/**
 * @author liuxinxin
 * @date 2023/8/2 上午10:39
 */

@Component
@RequiredArgsConstructor
public class DashboardProjectManage {

    private final IProjectService iProjectService;
    private final INdProjectDelayApplyService iProjectDelayApplyService;
    private final DashboardHelper dashboardHelper;
    private final IPurchaseService iPurchaseService;

    public DashboardProjectSummaryVO getProjectSummary(QueryYearPO queryYearPO) {
        // 预算年度
        Integer year = queryYearPO.getYear();
        String regionCode = queryYearPO.getRegionCode();
        List<Project> allProjectWithRepeatList = iProjectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Objects.nonNull(year), Project::getProjectYear, year)
                .eq(StringUtils.isNotBlank(regionCode), Project::getAreaCode, regionCode)
        );
        List<Project> allProjectList = allProjectWithRepeatList.stream()
                .filter(r -> r.getNewest()).collect(Collectors.toList());

        List<Long> allProjectIdWithRepeatList = allProjectWithRepeatList.stream().map(Project::getId).collect(Collectors.toList());

        // 项目总数
        Integer projectCnt = allProjectList.size();

        // 待立项项目数
        List<Project> toBeApprovedProjectList = allProjectList.stream()
                .filter(r -> ProjectStatusEnum.TO_BE_APPROVED.getCode().equals(r.getStatus()))
                .collect(Collectors.toList());
        Integer toBeApprovedProjectCnt = toBeApprovedProjectList.size();

        // 已立项项目数
        Integer approvedProjectCnt = projectCnt - toBeApprovedProjectCnt;

        // 项目立项率
        Double projectApprovalRate = new BigDecimal((float) approvedProjectCnt / projectCnt).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

        // 项目申报总金额
        List<BigDecimal> declareAmountList = allProjectList.stream().filter(r -> Objects.nonNull(r.getDeclareAmount()))
                .map(Project::getDeclareAmount).
                        collect(Collectors.toList());
        BigDecimal declareAmountSum = new BigDecimal("0");
        for (BigDecimal declareAmount : declareAmountList) {
            declareAmountSum.add(declareAmount);
        }

        // 项目批复总金额
        List<BigDecimal> approvedTotalInvestmentIncreaseList = allProjectList.stream().filter(r -> Objects.nonNull(r.getApprovedTotalInvestmentIncrease()))
                .map(Project::getApprovedTotalInvestmentIncrease)
                .collect(Collectors.toList());
        BigDecimal approvedTotalInvestmentIncreaseSum = new BigDecimal("0");
        for (BigDecimal approvedTotalInvestmentIncrease : approvedTotalInvestmentIncreaseList) {
            approvedTotalInvestmentIncreaseSum.add(approvedTotalInvestmentIncrease);
        }

        // 资金核定率
        BigDecimal fundApprovalRate = new BigDecimal("0");
        if (new BigDecimal("0").compareTo(approvedTotalInvestmentIncreaseSum) != 0) {
            fundApprovalRate = declareAmountSum.divide(approvedTotalInvestmentIncreaseSum, 2, BigDecimal.ROUND_HALF_UP);
        }


        // 项目采购总金额
        BigDecimal projectProcurementTotalAmount = new BigDecimal("0");
        List<Purchase> purchaseList = iPurchaseService.list(Wrappers.lambdaQuery(Purchase.class)
                .in(Purchase::getProjectId, allProjectIdWithRepeatList));
        for (Purchase purchase : purchaseList) {
            BigDecimal transactionAmount = purchase.getTransactionAmount();
            if (Objects.nonNull(transactionAmount)) {
                projectProcurementTotalAmount.add(transactionAmount);
            }
        }

//        项目画像

        // 延期项目数 延期占比
        List<ProjectDelayApply> projectDelayApplyList = iProjectDelayApplyService
                .list(Wrappers.lambdaQuery(ProjectDelayApply.class)
                        .in(ProjectDelayApply::getProjectId, allProjectIdWithRepeatList));
        Map<Long, List<ProjectDelayApply>> projectDelayApplyListMap = projectDelayApplyList.stream().collect(Collectors.groupingBy(ProjectDelayApply::getProjectId));
        Integer delayProjectCnt = projectDelayApplyListMap.keySet().size();
        Double delayProportion = new BigDecimal((float) delayProjectCnt / projectCnt).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();

        // 项目变更数量 项目变更金额
        List<Project> changedProjectList = new ArrayList<>();
        Map<String, List<Project>> allProjectMap = allProjectWithRepeatList.stream().collect(Collectors.groupingBy(Project::getProjectCode));
        for (String projectCode : allProjectMap.keySet()) {
            List<Project> projectList = allProjectMap.get(projectCode);
            Project newestProject = projectList.stream()
                    .filter(r -> r.getNewest())
                    .collect(Collectors.toList()).get(0);
            Boolean isChanged = false;
            for (Project project : projectList) {
                Boolean newest = project.getNewest();
                Boolean isBackReject = project.getIsBackReject();
                if (!newest && isBackReject) {
                    isChanged = true;
                    break;
                }
            }
            if (isChanged) {
                changedProjectList.add(newestProject);
            }
        }
        Integer changedProjectCnt = changedProjectList.size();

        // 项目变更金额
        BigDecimal changedProjectContractAmountSum = new BigDecimal("0");
        for (Project project : changedProjectList) {
            BigDecimal contractAmount = project.getContractAmount();
            if (Objects.nonNull(contractAmount)) {
                changedProjectContractAmountSum.add(contractAmount);
            }
        }

        // 装配返回VO
        DashboardProjectSummaryVO dashboardProjectSummaryVO = new DashboardProjectSummaryVO();
        dashboardProjectSummaryVO.setProjectCnt(projectCnt);
        dashboardProjectSummaryVO.setApprovedProjectCnt(approvedProjectCnt);
        dashboardProjectSummaryVO.setToBeApprovedProjectCnt(toBeApprovedProjectCnt);
        dashboardProjectSummaryVO.setProjectApprovalRate(projectApprovalRate);
        dashboardProjectSummaryVO.setDeclareAmountSum(declareAmountSum);
        dashboardProjectSummaryVO.setApprovedTotalInvestmentIncreaseSum(approvedTotalInvestmentIncreaseSum);

        dashboardProjectSummaryVO.setDelayProjectCnt(delayProjectCnt);
        dashboardProjectSummaryVO.setDelayProportion(delayProportion);
        dashboardProjectSummaryVO.setChangedProjectCnt(changedProjectCnt);
        dashboardProjectSummaryVO.setChangedProjectContractAmountSum(changedProjectContractAmountSum);
        dashboardProjectSummaryVO.setFundApprovalRate(fundApprovalRate);
        return dashboardProjectSummaryVO;
    }

    public DashboardProjectCntSummaryVO getProjectCntSummary(QueryYearPO queryYearPO) {
        // 预算年度
        Integer year = queryYearPO.getYear();
        String regionCode = queryYearPO.getRegionCode();
        List<Project> allProjectList = iProjectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Project::getNewest, true)
                .eq(Objects.nonNull(year), Project::getProjectYear, year)
                .eq(StringUtils.isNotBlank(regionCode), Project::getAreaCode, regionCode)
        );

        // 单位项目数量TOP5
        List<CompanyProjectCntBO> companyProjectCntTop5List = new ArrayList<>();
        Map<String, List<Project>> buildOrgNameProjectGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getBuildOrgName));
        for (String buildOrgName : buildOrgNameProjectGroupMap.keySet()) {
            List<Project> projectList = buildOrgNameProjectGroupMap.get(buildOrgName);
            CompanyProjectCntBO companyProjectCntBO = new CompanyProjectCntBO();
            companyProjectCntBO.setBuildOrgName(buildOrgName);
            companyProjectCntBO.setProjectCnt(projectList.size());
            companyProjectCntTop5List.add(companyProjectCntBO);
        }
        companyProjectCntTop5List = companyProjectCntTop5List.stream()
                .sorted(Comparator.comparing(CompanyProjectCntBO::getProjectCnt).reversed())
                .collect(Collectors.toList());
        if (companyProjectCntTop5List.size() > 5) {
            companyProjectCntTop5List = companyProjectCntTop5List.subList(0, 5);
        }

        // 项目增补情况
        Map<Integer, List<Project>> isTemporaryAugmentGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getIsTemporaryAugment));
        Map<Integer, String> temporaryAugmentMap = dashboardHelper.getTemporaryAugmentMap();
        AnalysisChart isTemporaryAugmentAnalysisChart = DashboardChartAssembler.buildAnalysisChart(temporaryAugmentMap, isTemporaryAugmentGroupMap
                , ChartTypeEnum.PROJECT_SUPPLEMENTATION_STATUS_CHART);

        // 各类型项目数量
        Map<Integer, List<Project>> projectTypeGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getProjectType));
        Map<Integer, String> projectTypeMap = dashboardHelper.getTemporaryAugmentMap();
        AnalysisChart projectTypeAnalysisChart = DashboardChartAssembler.buildAnalysisChart(projectTypeMap, projectTypeGroupMap
                , ChartTypeEnum.EACH_TYPE_QUANTITY_OF_PROJECT_CHART);

        // 各区域项目数量
        Map<String, List<Project>> areaCodeGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getAreaCode));
        Map<String, String> liShuiRegionCodeNameMap = dashboardHelper.getLiShuiRegionCodeNameMap();
        AnalysisChart areaCodeAnalysisChart = DashboardChartAssembler.buildAnalysisChart(liShuiRegionCodeNameMap, areaCodeGroupMap
                , ChartTypeEnum.PROJECTS_NUMBER_IN_EACH_REGION_CHART);

        // 各领域项目数量
        Map<Integer, List<Project>> bizDomainGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getBizDomain));
        Map<Integer, String> bizDomainMap = dashboardHelper.getBizDomainMap();
        AnalysisChart bizDomainAnalysisChart = DashboardChartAssembler.buildAnalysisChart(bizDomainMap, bizDomainGroupMap
                , ChartTypeEnum.PROJECTS_NUMBER_IN_VARIOUS_FIELDS_CHART);

        // 各阶段项目数量
        Map<Integer, List<Project>> projectStateGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getStage));
        AnalysisChart projectStateAnalysisChart = DashboardChartAssembler
                .buildProjectStateAnalysisChart(projectStateGroupMap, ChartTypeEnum.PROJECTS_NUMBER_IN_EACH_STAGE_CHART);

        DashboardProjectCntSummaryVO dashboardProjectCntSummaryVO = new DashboardProjectCntSummaryVO();
        dashboardProjectCntSummaryVO.setCompanyProjectCntTop5List(companyProjectCntTop5List);
        List<AnalysisChart> analysisChartList = new ArrayList<>();
        dashboardProjectCntSummaryVO.setAnalysisChartList(analysisChartList);
        analysisChartList.add(isTemporaryAugmentAnalysisChart);
        analysisChartList.add(projectTypeAnalysisChart);
        analysisChartList.add(bizDomainAnalysisChart);
        analysisChartList.add(areaCodeAnalysisChart);
        analysisChartList.add(projectStateAnalysisChart);
        return dashboardProjectCntSummaryVO;
    }


    public DashboardInvestmentSummaryVO getInvestmentSummary(QueryYearPO queryYearPO) {
        // 预算年度
        Integer year = queryYearPO.getYear();
        String regionCode = queryYearPO.getRegionCode();
        List<Project> allProjectList = iProjectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Project::getNewest, true)
                .eq(Objects.nonNull(year), Project::getProjectYear, year)
                .eq(StringUtils.isNotBlank(regionCode), Project::getAreaCode, regionCode)
        );

        // 项目预算TOP5
        List<ProjectATIISBO> projectATIISTop5List = allProjectList.stream().filter(r -> Objects.nonNull(r.getApprovedTotalInvestmentIncrease()))
                .map(r -> {
                    ProjectATIISBO projectATIISBO = new ProjectATIISBO();
                    projectATIISBO.setProjectId(r.getId());
                    projectATIISBO.setProjectCode(r.getProjectCode());
                    projectATIISBO.setProjectName(r.getProjectName());
                    projectATIISBO.setApprovedTotalInvestmentIncrease(r.getApprovedTotalInvestmentIncrease());
                    return projectATIISBO;
                }).collect(Collectors.toList());
        projectATIISTop5List = projectATIISTop5List.stream()
                .sorted(Comparator.comparing(ProjectATIISBO::getApprovedTotalInvestmentIncrease)
                        .reversed()).collect(Collectors.toList());
        if (projectATIISTop5List.size() > 5) {
            projectATIISTop5List = projectATIISTop5List.subList(0, 5);
        }

        // 单位预算TOP5
        List<CompanyProjectCntBO> companyProjectATIISTop5List = new ArrayList<>();
        Map<String, List<Project>> buildOrgNameProjectGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getBuildOrgName));
        for (String buildOrgName : buildOrgNameProjectGroupMap.keySet()) {
            List<Project> projectList = buildOrgNameProjectGroupMap.get(buildOrgName);
            CompanyProjectCntBO companyProjectCntBO = new CompanyProjectCntBO();
            companyProjectCntBO.setBuildOrgName(buildOrgName);
            BigDecimal approvedTotalInvestmentIncreaseSum = new BigDecimal("0");
            for (Project project : projectList) {
                BigDecimal approvedTotalInvestmentIncrease = project.getApprovedTotalInvestmentIncrease();
                if (Objects.nonNull(approvedTotalInvestmentIncrease)) {
                    approvedTotalInvestmentIncreaseSum.add(approvedTotalInvestmentIncrease);
                }
            }
            companyProjectCntBO.setApprovedTotalInvestmentIncreaseSum(approvedTotalInvestmentIncreaseSum);
            companyProjectATIISTop5List.add(companyProjectCntBO);
        }
        companyProjectATIISTop5List = companyProjectATIISTop5List.stream()
                .sorted(Comparator.comparing(CompanyProjectCntBO::getApprovedTotalInvestmentIncreaseSum).reversed())
                .collect(Collectors.toList());
        if (companyProjectATIISTop5List.size() > 5) {
            companyProjectATIISTop5List = companyProjectATIISTop5List.subList(0, 5);
        }

        // 各领域项目投资情况
        Map<Integer, List<Project>> bizDomainGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getBizDomain));
        Map<Integer, String> bizDomainMap = dashboardHelper.getBizDomainMap();
        AnalysisChart bizDomainInvestmentAnalysisChart = DashboardChartAssembler.buildInvestmentAnalysisChart(bizDomainMap, bizDomainGroupMap
                , ChartTypeEnum.PROJECTS_INVESTMENT_AMOUNT_IN_VARIOUS_FIELDS_CHART);

        // 各区域项目投资情况
        Map<String, List<Project>> areaCodeGroupMap = allProjectList.stream()
                .collect(Collectors.groupingBy(Project::getAreaCode));
        Map<String, String> liShuiRegionCodeNameMap = dashboardHelper.getLiShuiRegionCodeNameMap();
        AnalysisChart areaCodeInvestmentAnalysisChart = DashboardChartAssembler.buildInvestmentAnalysisChart(liShuiRegionCodeNameMap, areaCodeGroupMap
                , ChartTypeEnum.PROJECTS_INVESTMENT_SITUATION_IN_VARIOUS_REGIONS);

        DashboardInvestmentSummaryVO dashboardInvestmentSummaryVO = new DashboardInvestmentSummaryVO();
        dashboardInvestmentSummaryVO.setCompanyProjectATIISTop5List(companyProjectATIISTop5List);
        dashboardInvestmentSummaryVO.setProjectATIISTop5List(projectATIISTop5List);
        List<AnalysisChart> analysisChartList = new ArrayList<>();
        dashboardInvestmentSummaryVO.setAnalysisChartList(analysisChartList);
        analysisChartList.add(areaCodeInvestmentAnalysisChart);
        analysisChartList.add(bizDomainInvestmentAnalysisChart);
        return dashboardInvestmentSummaryVO;
    }

}
