package cn.palmte.work.service;

import cn.palmte.work.bean.CashFlowStatisticsBean;
import cn.palmte.work.bean.PrimaryIndicatorBean;
import cn.palmte.work.bean.ProfitAndLossBean;
import cn.palmte.work.bean.StatisticsBean;
import cn.palmte.work.model.*;
import cn.palmte.work.utils.InterfaceUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.jfunc.common.db.utils.Pagination;
import top.jfunc.common.utils.CollectionUtil;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
public class StatisticsService {

    @Autowired
    private ProjectBudgetCostRepository projectBudgetCostRepository;

    @Autowired
    private ProjectBudgetIncomeRepository projectBudgetIncomeRepository;

    @Autowired
    private ProjectBudgetCostManageRepository projectBudgetCostManageRepository;

    @Autowired
    private ProjectSettleCostRepository projectSettleCostRepository;

    @Autowired
    private ProjectSettleIncomeRepository projectSettleIncomeRepository;

    @Autowired
    private ProjectSettleCostManageRepository projectSettleCostManageRepository;

    @Autowired
    private ProjectBudgetPlanDetailRepository projectBudgetPlanDetailRepository;

    @Autowired
    private ProjectSettleCashFlowRepository projectSettleCashFlowRepository;

    @Autowired
    private ProjectSettleProfitMarginRepository projectSettleProfitMarginRepository;

    @Autowired
    private ProjectVisibleRepository projectVisibleRepository;

    @Autowired
    private SysRoleRepository sysRoleRepository;

    @Autowired
    private Pagination pagination;

    /**
     * 分月项目统计 获取主要指标数据、损益表
     *
     * @return
     */
    public StatisticsBean getStatisticsData() {
        StatisticsBean statisticsBean = new StatisticsBean();
        List<PrimaryIndicatorBean> list = new ArrayList<>();
        List<ProfitAndLossBean> profitAndLossList = new ArrayList<>();

        PrimaryIndicatorBean include = new PrimaryIndicatorBean();
        PrimaryIndicatorBean exclude = new PrimaryIndicatorBean();

        ProfitAndLossBean profitAndLossBeanInclude = new ProfitAndLossBean();
        ProfitAndLossBean profitAndLossBeanExclude = new ProfitAndLossBean();
        profitAndLossBeanInclude.setTitle("预算金额（含税）");
        profitAndLossBeanExclude.setTitle("预算金额（不含税）");
        include.setTitle("预算金额（含税）");
        exclude.setTitle("预算金额（不含税）");

        Admin admin = InterfaceUtil.getAdmin();
        List<Project> projectList = null;
        //项目可见性，根据角色和人员id
        int roleId = admin.getRoleId();
        Integer adminId = admin.getId();
        String sql = "select proj.id, proj.name, proj.approve_status_settle from project_settle_cost psc left join project proj on psc.project_id = proj.id ";
        //自己创建的肯定能看见，配置的可以看见，系统管理员可以看见
        SysRole sysRole = sysRoleRepository.findSysRoleById(roleId);
        if(SysRole.ROLE_TYPE_SYSTEM != sysRole.getType()){
            sql = sql + " where (proj.creator_id=? OR proj.id in (SELECT pv1.project_id FROM project_visible pv1 WHERE pv1.type=1 AND pv1.tid=? UNION SELECT pv2.project_id FROM project_visible pv2 WHERE pv2.type=2 AND pv2.tid=?)) group by proj.id order by proj.id asc";
            projectList = pagination.find(sql, Project.class, adminId, roleId, adminId);
        } else {
            sql = sql + " group by proj.id order by proj.id asc";
            projectList = pagination.find(sql, Project.class);
        }
        List<Project> projects = new ArrayList<>();
        List<Integer> projectIds = new ArrayList<>();
        for (Project project : projectList) {
            if (project.getApproveStatusSettle() == 2) {
                projects.add(project);
                projectIds.add(project.getId());
                continue;
            }
        }

        if(CollectionUtil.isEmpty(projectIds)){
            List<CashFlowStatisticsBean> cashFlow = new ArrayList<>();
            CashFlowStatisticsBean cashFlowStatisticsBean = new CashFlowStatisticsBean();
            cashFlowStatisticsBean.setTitle("预算金额");
            list.add(include);
            list.add(exclude);
            profitAndLossList.add(profitAndLossBeanInclude);
            profitAndLossList.add(profitAndLossBeanExclude);
            cashFlow.add(cashFlowStatisticsBean);
            statisticsBean.setPrimaryIndicatorBeanList(list);
            statisticsBean.setProfitAndLossBeanList(profitAndLossList);
            statisticsBean.setCashFlowStatisticsBeanList(cashFlow);
            return statisticsBean;
        }

        //收入数据
        List<ProjectBudgetIncome> allIncome = projectBudgetIncomeRepository.findAllByProjectIds(projectIds);
        if (CollectionUtil.isNotEmpty(allIncome)) {
            BigDecimal deviceIncomeTaxIncludeSum = allIncome.stream().filter(d -> d.getType() == ProjectBudgetIncome.TYPE_DEVICE).map(ProjectBudgetIncome::getIncomeTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal engineerIncomeTaxIncludeSum = allIncome.stream().filter(d -> d.getType() == ProjectBudgetIncome.TYPE_ENGINEER).map(ProjectBudgetIncome::getIncomeTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal serviceIncomeTaxIncludeSum = allIncome.stream().filter(d -> d.getType() == ProjectBudgetIncome.TYPE_SERVICE).map(ProjectBudgetIncome::getIncomeTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            include.setIncomeDevice(deviceIncomeTaxIncludeSum);
            include.setIncomeEngineer(engineerIncomeTaxIncludeSum);
            include.setIncomeService(serviceIncomeTaxIncludeSum);

            BigDecimal deviceIncomeTaxExcludeSum = allIncome.stream().filter(d -> d.getType() == ProjectBudgetIncome.TYPE_DEVICE).map(ProjectBudgetIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal engineerIncomeTaxExcludeSum = allIncome.stream().filter(d -> d.getType() == ProjectBudgetIncome.TYPE_ENGINEER).map(ProjectBudgetIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal serviceIncomeTaxExcludeSum = allIncome.stream().filter(d -> d.getType() == ProjectBudgetIncome.TYPE_SERVICE).map(ProjectBudgetIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            exclude.setIncomeDevice(deviceIncomeTaxExcludeSum);
            exclude.setIncomeEngineer(engineerIncomeTaxExcludeSum);
            exclude.setIncomeService(serviceIncomeTaxExcludeSum);

            BigDecimal incomeInclude = allIncome.stream().map(ProjectBudgetIncome::getIncomeTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            profitAndLossBeanInclude.setIncome(incomeInclude);
            BigDecimal incomeExclude = allIncome.stream().map(ProjectBudgetIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            profitAndLossBeanExclude.setIncome(incomeExclude);
        }

        //成本数据
        List<ProjectBudgetCost> allCost = projectBudgetCostRepository.findAllByProjectIds(projectIds);
        if (CollectionUtil.isNotEmpty(allCost)) {

            BigDecimal deviceCostTaxIncludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_DEVICE).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal buildingCostTaxIncludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_BUILDING).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal serviceCostTaxIncludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_SERVICE).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal otherCostTaxIncludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_OTHER).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            //BigDecimal projectManageCostTaxIncludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_PROJECT_MANAGE).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal otherOtherCostTaxIncludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_OTHER_OTHER).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            include.setCostPurchaseDevice(deviceCostTaxIncludeSum);
            include.setCostPurchaseBuild(buildingCostTaxIncludeSum);
            include.setCostPurchaseService(serviceCostTaxIncludeSum);
            include.setCostPurchaseOther(otherCostTaxIncludeSum);
            //include.setCostProjectManage(projectManageCostTaxIncludeSum);
            include.setCostOtherOther(otherOtherCostTaxIncludeSum);

            BigDecimal deviceCostTaxExcludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_DEVICE).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal buildingCostTaxExcludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_BUILDING).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal serviceCostTaxExcludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_SERVICE).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal otherCostTaxExcludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_OTHER).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal projectManageCostTaxExcludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_PROJECT_MANAGE).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal otherOtherCostTaxExcludeSum = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_OTHER_OTHER).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            exclude.setCostPurchaseDevice(deviceCostTaxExcludeSum);
            exclude.setCostPurchaseBuild(buildingCostTaxExcludeSum);
            exclude.setCostPurchaseService(serviceCostTaxExcludeSum);
            exclude.setCostPurchaseOther(otherCostTaxExcludeSum);
            exclude.setCostProjectManage(projectManageCostTaxExcludeSum);
            exclude.setCostOtherOther(otherOtherCostTaxExcludeSum);

            BigDecimal costInclude = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_DEVICE || d.getType() == ProjectBudgetCost.TYPE_BUILDING || d.getType() == ProjectBudgetCost.TYPE_SERVICE).map(ProjectBudgetCost::getCostTaxInclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal costExclude = allCost.stream().filter(d -> d.getType() == ProjectBudgetCost.TYPE_DEVICE || d.getType() == ProjectBudgetCost.TYPE_BUILDING || d.getType() == ProjectBudgetCost.TYPE_SERVICE).map(ProjectBudgetCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            profitAndLossBeanInclude.setCost(costInclude);
            //profitAndLossBeanInclude.setManageCost(projectManageCostTaxIncludeSum);
            profitAndLossBeanInclude.setOther(otherCostTaxIncludeSum.add(otherOtherCostTaxIncludeSum));

            profitAndLossBeanExclude.setCost(costExclude);
            profitAndLossBeanInclude.setManageCost(projectManageCostTaxExcludeSum);
            profitAndLossBeanExclude.setOther(otherCostTaxExcludeSum.add(otherOtherCostTaxExcludeSum));

        }

        //管理成本数据
        List<ProjectBudgetCostManage> allCostManage = projectBudgetCostManageRepository.findAllByProjectIds(projectIds);
        if (CollectionUtil.isNotEmpty(allCostManage)) {
            BigDecimal expropriationSum = allCostManage.stream().filter(d -> d.getType() == ProjectBudgetCostManage.TYPE_EXPROPRIATION).map(ProjectBudgetCostManage::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal companyManageSum = allCostManage.stream().filter(d -> d.getType() == ProjectBudgetCostManage.TYPE_COMPANY_MANAGE).map(ProjectBudgetCostManage::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            exclude.setCostExpropriation(expropriationSum);
            exclude.setCostCompanyManage(companyManageSum);

            profitAndLossBeanExclude.setExpropriation(expropriationSum);
            profitAndLossBeanExclude.setCompanyManage(companyManageSum);
        }

        list.add(include);
        list.add(exclude);
        profitAndLossList.add(profitAndLossBeanInclude);
        profitAndLossList.add(profitAndLossBeanExclude);

        PrimaryIndicatorBean allSettle = new PrimaryIndicatorBean();
        ProfitAndLossBean allProfitAndLoss = new ProfitAndLossBean();
        allSettle.setTitle("实际累计（不含税）");
        allProfitAndLoss.setTitle("实际累计（不含税）");

        List<ProjectSettleIncome> allSettleIncome = projectSettleIncomeRepository.findAllByProjectIds(projectIds);
        if (CollectionUtil.isNotEmpty(allSettleIncome)) {
            BigDecimal incomeDeviceAll = allSettleIncome.stream().filter(d -> d.getType() == ProjectSettleIncome.TYPE_DEVICE).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal incomeEngineerAll = allSettleIncome.stream().filter(d -> d.getType() == ProjectSettleIncome.TYPE_ENGINEER).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal incomeServiceAll = allSettleIncome.stream().filter(d -> d.getType() == ProjectSettleIncome.TYPE_SERVICE).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            allSettle.setIncomeDevice(incomeDeviceAll);
            allSettle.setIncomeEngineer(incomeEngineerAll);
            allSettle.setIncomeService(incomeServiceAll);

            BigDecimal incomeExclude = allSettleIncome.stream().map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            allProfitAndLoss.setIncome(incomeExclude);
        }

        List<ProjectSettleCost> allSettleCost = projectSettleCostRepository.findAllByProjectIds(projectIds);
        if (CollectionUtil.isNotEmpty(allSettleCost)) {
            BigDecimal costDeviceAll = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_DEVICE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal costBuildingAll = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_BUILDING).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal costServiceAll = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_SERVICE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal costOtherAll = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_OTHER).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal costProjectManageAll = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_PROJECT_MANAGE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal costOtherOtherAll = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_OTHER_OTHER).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            allSettle.setCostPurchaseDevice(costDeviceAll);
            allSettle.setCostPurchaseBuild(costBuildingAll);
            allSettle.setCostPurchaseService(costServiceAll);
            allSettle.setCostPurchaseOther(costOtherAll);
            allSettle.setCostProjectManage(costProjectManageAll);
            allSettle.setCostOtherOther(costOtherOtherAll);

            BigDecimal cost = allSettleCost.stream().filter(d -> d.getType() == ProjectSettleCost.TYPE_DEVICE || d.getType() == ProjectSettleCost.TYPE_BUILDING || d.getType() == ProjectSettleCost.TYPE_SERVICE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            allProfitAndLoss.setCost(cost);
            allProfitAndLoss.setManageCost(costProjectManageAll);
            allProfitAndLoss.setOther(costOtherAll.add(costOtherOtherAll));

        }

        List<ProjectSettleCostManage> allSettleCostManage = projectSettleCostManageRepository.findAllByProjectIds(projectIds);
        if (CollectionUtil.isNotEmpty(allSettleCostManage)) {
            BigDecimal expropriationAll = allSettleCostManage.stream().filter(d -> d.getType() == ProjectSettleCostManage.TYPE_EXPROPRIATION).map(ProjectSettleCostManage::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal companyManageAll = allSettleCostManage.stream().filter(d -> d.getType() == ProjectSettleCostManage.TYPE_COMPANY_MANAGE).map(ProjectSettleCostManage::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

            allSettle.setCostExpropriation(expropriationAll);
            allSettle.setCostCompanyManage(companyManageAll);

            allProfitAndLoss.setExpropriation(expropriationAll);
            allProfitAndLoss.setCompanyManage(companyManageAll);
        }

        List<ProjectSettleProfitMargin> profitMargins = projectSettleProfitMarginRepository.findAllByProjectIds(projectIds);
        if(CollectionUtil.isNotEmpty(profitMargins)){
            BigDecimal typeGrossProfit = profitMargins.stream().filter(d -> d.getType() == ProjectSettleProfitMargin.TYPE_GROSS_PROFIT).map(ProjectSettleProfitMargin::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal typeContributionProfit = profitMargins.stream().filter(d -> d.getType() == ProjectSettleProfitMargin.TYPE_CONTRIBUTION_PROFIT).map(ProjectSettleProfitMargin::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal typeNetProfit = profitMargins.stream().filter(d -> d.getType() == ProjectSettleProfitMargin.TYPE_NET_PROFIT).map(ProjectSettleProfitMargin::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

            allProfitAndLoss.setGrossProfit(typeGrossProfit);
            allProfitAndLoss.setContributionMargin(typeContributionProfit);
            allProfitAndLoss.setNetMargin(typeNetProfit);
        }

        list.add(allSettle);
        profitAndLossList.add(allProfitAndLoss);

        List<String> projectTime = projectSettleIncomeRepository.getProjectTime();
        if (CollectionUtil.isNotEmpty(projectTime)) {
            for (String time : projectTime) {

                PrimaryIndicatorBean primaryIndicatorBean = new PrimaryIndicatorBean();
                ProfitAndLossBean profitAndLossBean = new ProfitAndLossBean();
                primaryIndicatorBean.setTitle(time);
                profitAndLossBean.setTitle(time);

                BigDecimal incomeDevice = allSettleIncome.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleIncome.TYPE_DEVICE).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal incomeEngineer = allSettleIncome.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleIncome.TYPE_ENGINEER).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal incomeService = allSettleIncome.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleIncome.TYPE_SERVICE).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

                primaryIndicatorBean.setIncomeDevice(incomeDevice);
                primaryIndicatorBean.setIncomeEngineer(incomeEngineer);
                primaryIndicatorBean.setIncomeService(incomeService);

                BigDecimal income = allSettleIncome.stream().filter(d -> d.getTime().equals(time)).map(ProjectSettleIncome::getIncomeTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                profitAndLossBean.setIncome(income);

                BigDecimal costDevice = allSettleCost.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCost.TYPE_DEVICE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal costBuilding = allSettleCost.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCost.TYPE_BUILDING).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal costService = allSettleCost.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCost.TYPE_SERVICE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal costOther = allSettleCost.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCost.TYPE_OTHER).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal costProjectManage = allSettleCost.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCost.TYPE_PROJECT_MANAGE).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal costOtherOther = allSettleCost.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCost.TYPE_OTHER_OTHER).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

                primaryIndicatorBean.setCostPurchaseDevice(costDevice);
                primaryIndicatorBean.setCostPurchaseBuild(costBuilding);
                primaryIndicatorBean.setCostPurchaseService(costService);
                primaryIndicatorBean.setCostPurchaseOther(costOther);
                primaryIndicatorBean.setCostProjectManage(costProjectManage);
                primaryIndicatorBean.setCostOtherOther(costOtherOther);

                BigDecimal cost = allSettleCost.stream().filter(d -> d.getTime().equals(time) && (d.getType() == ProjectSettleCost.TYPE_DEVICE || d.getType() == ProjectSettleCost.TYPE_BUILDING || d.getType() == ProjectSettleCost.TYPE_SERVICE)).map(ProjectSettleCost::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                profitAndLossBean.setCost(cost);
                profitAndLossBean.setManageCost(costProjectManage);
                profitAndLossBean.setOther(costOther.add(costOtherOther));

                BigDecimal expropriation = allSettleCostManage.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCostManage.TYPE_EXPROPRIATION).map(ProjectSettleCostManage::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal companyManage = allSettleCostManage.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCostManage.TYPE_COMPANY_MANAGE).map(ProjectSettleCostManage::getCostTaxExclude).reduce(BigDecimal.ZERO, BigDecimal::add);

                primaryIndicatorBean.setCostExpropriation(expropriation);
                primaryIndicatorBean.setCostCompanyManage(companyManage);

                profitAndLossBean.setExpropriation(expropriation);
                profitAndLossBean.setCompanyManage(companyManage);

                BigDecimal typeGrossProfit = profitMargins.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleProfitMargin.TYPE_GROSS_PROFIT).map(ProjectSettleProfitMargin::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal typeContributionProfit = profitMargins.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleProfitMargin.TYPE_CONTRIBUTION_PROFIT).map(ProjectSettleProfitMargin::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal typeNetProfit = profitMargins.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleProfitMargin.TYPE_NET_PROFIT).map(ProjectSettleProfitMargin::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

                BigDecimal divide2 = profitAndLossBean.getIncome();
                BigDecimal min = BigDecimal.valueOf(0.01);
                if (divide2.compareTo(min) < 0 && divide2.compareTo(BigDecimal.valueOf(-0.01)) > 0) {
                    divide2 = BigDecimal.ONE;
                }
                profitAndLossBean.setGrossProfit(typeGrossProfit);
                profitAndLossBean.setGrossProfitProfit(profitAndLossBean.getGrossProfit().multiply(new BigDecimal(100)).divide(divide2, 4, BigDecimal.ROUND_HALF_UP));
                profitAndLossBean.setContributionMargin(typeContributionProfit);
                profitAndLossBean.setContributionMarginProfit(profitAndLossBean.getContributionMargin().multiply(new BigDecimal(100)).divide(divide2, 4, BigDecimal.ROUND_HALF_UP));
                profitAndLossBean.setNetMargin(typeNetProfit);
                profitAndLossBean.setNetMarginProfit(profitAndLossBean.getNetMargin().multiply(new BigDecimal(100)).divide(divide2, 4, BigDecimal.ROUND_HALF_UP));

                list.add(primaryIndicatorBean);
                profitAndLossList.add(profitAndLossBean);
            }
        }

        List<CashFlowStatisticsBean> cashFlow = getCashFlow(projectIds);

        statisticsBean.setPrimaryIndicatorBeanList(list);
        statisticsBean.setProfitAndLossBeanList(profitAndLossList);
        statisticsBean.setCashFlowStatisticsBeanList(cashFlow);
        return statisticsBean;
    }

    /**
     * 分月项目统计 获取现金流量表数据
     *
     * @return
     */
    public List<CashFlowStatisticsBean> getCashFlow(List<Integer> projectIds) {
        List<CashFlowStatisticsBean> list = new ArrayList<>();

        CashFlowStatisticsBean cashFlowStatisticsBean = new CashFlowStatisticsBean();
        cashFlowStatisticsBean.setTitle("预算金额");
        List<ProjectBudgetPlanDetail> cashFlows = projectBudgetPlanDetailRepository.findAllByProjectIds(projectIds);

        BigDecimal saleIncome = cashFlows.stream().map(ProjectBudgetPlanDetail::getSaleIncome).reduce(BigDecimal.ZERO, BigDecimal::add);
        cashFlowStatisticsBean.setSaleIncomeCash(saleIncome);

        BigDecimal earnestMoneyIncome = cashFlows.stream().map(ProjectBudgetPlanDetail::getEarnestMoneyIncome).reduce(BigDecimal.ZERO, BigDecimal::add);
        cashFlowStatisticsBean.setEarnestMoneyIncome(earnestMoneyIncome);

        BigDecimal deviceCost = cashFlows.stream().map(ProjectBudgetPlanDetail::getDeviceCost).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal engineerCost = cashFlows.stream().map(ProjectBudgetPlanDetail::getEngineerCost).reduce(BigDecimal.ZERO, BigDecimal::add);
        cashFlowStatisticsBean.setPurchaseCost(deviceCost.add(engineerCost));

        BigDecimal projectManageCost = cashFlows.stream().map(ProjectBudgetPlanDetail::getProjectManageCost).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal earnestMoneyCost = cashFlows.stream().map(ProjectBudgetPlanDetail::getEarnestMoneyCost).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal capitalInterest = cashFlows.stream().map(ProjectBudgetPlanDetail::getCapitalInterest).reduce(BigDecimal.ZERO, BigDecimal::add);
        cashFlowStatisticsBean.setEarnestMoneyCost(projectManageCost.add(earnestMoneyCost).add(capitalInterest));

        BigDecimal underWritten = cashFlows.stream().map(ProjectBudgetPlanDetail::getUnderwrittenPlan).reduce(BigDecimal.ZERO, BigDecimal::add);
        cashFlowStatisticsBean.setFinancingCapitalInflow(underWritten);

        BigDecimal repaymentPlan = cashFlows.stream().map(ProjectBudgetPlanDetail::getRepaymentPlan).reduce(BigDecimal.ZERO, BigDecimal::add);
        cashFlowStatisticsBean.setFinancingCapitalOutflow(repaymentPlan);

        cashFlowStatisticsBean.setNetCashFlow(saleIncome.add(earnestMoneyIncome).subtract(cashFlowStatisticsBean.getEarnestMoneyCost()));
        cashFlowStatisticsBean.setFinancingCapitalCashflow(underWritten.subtract(repaymentPlan));
        cashFlowStatisticsBean.setNetIncreaseMonetaryFunds(cashFlowStatisticsBean.getNetCashFlow().add(cashFlowStatisticsBean.getFinancingCapitalCashflow()));

        list.add(cashFlowStatisticsBean);

        List<String> projectTime = projectSettleCashFlowRepository.getProjectTime();
        List<ProjectSettleCashFlow> all = projectSettleCashFlowRepository.findAllByProjectIds(projectIds);

        CashFlowStatisticsBean cashFlowStatisticsAll = new CashFlowStatisticsBean();
        cashFlowStatisticsAll.setTitle("实际累计");

        BigDecimal saleIncomeCashAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.SALE_INCOME_CASH).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal taxReturnAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.TAX_RETURN).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal earnestMoneyIncomeTimeAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.EARNEST_MONEY_INCOME).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal purchaseCostAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.PURCHASE_COST).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal taxCostAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.TAX_COST).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal earnestMoneyCostTimeAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.EARNEST_MONEY_COST).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal netCashFlowAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.NET_CASH_FLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal cashInflowFromInvestingActivitiesAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.CASH_INFLOW_FROM_INVESTING_ACTIVITIES).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal cashOutflowFromInvestingActivitiesAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.CASH_OUTFLOW_FROM_INVESTING_ACTIVITIES).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal netCashFromInvestingActivitiesAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.NET_CASH_FROM_INVESTING_ACTIVITIES).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal financingCapitalInflowAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.FINANCING_CAPITAL_INFLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal financingCapitalOutflowAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.FINANCING_CAPITAL_OUTFLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal financingCapitalCashFlowAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.FINANCING_CAPITAL_CASHFLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal netIncreaseMonetaryFundsAll = all.stream().filter(d -> d.getType() == ProjectSettleCashFlow.NET_INCREASE_MONETARY_FUNDS).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

        cashFlowStatisticsAll.setSaleIncomeCash(saleIncomeCashAll);
        cashFlowStatisticsAll.setTaxReturn(taxReturnAll);
        cashFlowStatisticsAll.setEarnestMoneyIncome(earnestMoneyIncomeTimeAll);
        cashFlowStatisticsAll.setPurchaseCost(purchaseCostAll);
        cashFlowStatisticsAll.setTaxCost(taxCostAll);
        cashFlowStatisticsAll.setEarnestMoneyCost(earnestMoneyCostTimeAll);
        cashFlowStatisticsAll.setNetCashFlow(netCashFlowAll);
        cashFlowStatisticsAll.setCashInflowFromInvestingActivities(cashInflowFromInvestingActivitiesAll);
        cashFlowStatisticsAll.setCashOutflowFromInvestingActivities(cashOutflowFromInvestingActivitiesAll);
        cashFlowStatisticsAll.setNetCashFromInvestingActivities(netCashFromInvestingActivitiesAll);
        cashFlowStatisticsAll.setFinancingCapitalInflow(financingCapitalInflowAll);
        cashFlowStatisticsAll.setFinancingCapitalOutflow(financingCapitalOutflowAll);
        cashFlowStatisticsAll.setFinancingCapitalCashflow(financingCapitalCashFlowAll);
        cashFlowStatisticsAll.setNetIncreaseMonetaryFunds(netIncreaseMonetaryFundsAll);

        list.add(cashFlowStatisticsAll);

        if (CollectionUtil.isNotEmpty(projectTime)) {
            for (String time : projectTime) {
                CashFlowStatisticsBean cashFlowStatistics = new CashFlowStatisticsBean();
                cashFlowStatistics.setTitle(time);

                BigDecimal saleIncomeCash = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.SALE_INCOME_CASH).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal taxReturn = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.TAX_RETURN).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal earnestMoneyIncomeTime = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.EARNEST_MONEY_INCOME).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal purchaseCost = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.PURCHASE_COST).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal taxCost = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.TAX_COST).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal earnestMoneyCostTime = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.EARNEST_MONEY_COST).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal netCashFlow = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.NET_CASH_FLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal cashInflowFromInvestingActivities = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.CASH_INFLOW_FROM_INVESTING_ACTIVITIES).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal cashOutflowFromInvestingActivities = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.CASH_OUTFLOW_FROM_INVESTING_ACTIVITIES).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal netCashFromInvestingActivities = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.NET_CASH_FROM_INVESTING_ACTIVITIES).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal financingCapitalInflow = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.FINANCING_CAPITAL_INFLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal financingCapitalOutflow = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.FINANCING_CAPITAL_OUTFLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal financingCapitalCashFlow = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.FINANCING_CAPITAL_CASHFLOW).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                BigDecimal netIncreaseMonetaryFunds = all.stream().filter(d -> d.getTime().equals(time) && d.getType() == ProjectSettleCashFlow.NET_INCREASE_MONETARY_FUNDS).map(ProjectSettleCashFlow::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);

                cashFlowStatistics.setSaleIncomeCash(saleIncomeCash);
                cashFlowStatistics.setTaxReturn(taxReturn);
                cashFlowStatistics.setEarnestMoneyIncome(earnestMoneyIncomeTime);
                cashFlowStatistics.setPurchaseCost(purchaseCost);
                cashFlowStatistics.setTaxCost(taxCost);
                cashFlowStatistics.setEarnestMoneyCost(earnestMoneyCostTime);
                cashFlowStatistics.setNetCashFlow(netCashFlow);
                cashFlowStatistics.setCashInflowFromInvestingActivities(cashInflowFromInvestingActivities);
                cashFlowStatistics.setCashOutflowFromInvestingActivities(cashOutflowFromInvestingActivities);
                cashFlowStatistics.setNetCashFromInvestingActivities(netCashFromInvestingActivities);
                cashFlowStatistics.setFinancingCapitalInflow(financingCapitalInflow);
                cashFlowStatistics.setFinancingCapitalOutflow(financingCapitalOutflow);
                cashFlowStatistics.setFinancingCapitalCashflow(financingCapitalCashFlow);
                cashFlowStatistics.setNetIncreaseMonetaryFunds(netIncreaseMonetaryFunds);

                list.add(cashFlowStatistics);
            }
        }
        return list;
    }

}
