package com.hz.pm.api.projectlib.manage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.hz.pm.api.user.security.model.UserInfoDetails;
import com.hz.pm.api.user.util.LoginUserUtil;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.NdDateUtils;
import com.hz.pm.api.common.model.constant.BizConst;
import com.hz.pm.api.common.model.constant.CommonConst;
import com.hz.pm.api.common.model.constant.RegionConst;
import com.hz.pm.api.common.helper.RegionCacheHelper;
import com.hz.pm.api.common.util.ExcelDownUtil;
import com.hz.pm.api.common.util.ExcelExportStyle;
import com.hz.pm.api.datascope.model.DataScopeDTO;
import com.hz.pm.api.datascope.utils.DataScopeUtil;
import com.hz.pm.api.gov.model.entity.GovBizProjectApply;
import com.hz.pm.api.gov.model.entity.GovBizProjectApprove;
import com.hz.pm.api.gov.model.entity.GovBizProjectBaseinfo;
import com.hz.pm.api.gov.model.entity.GovOperationProjectBaseinfo;
import com.hz.pm.api.gov.service.IGovBizProjectApplyService;
import com.hz.pm.api.gov.service.IGovBizProjectApproveService;
import com.hz.pm.api.gov.service.IGovBizProjectBaseinfoService;
import com.hz.pm.api.gov.service.IGovOperationProjectBaseinfoService;
import com.hz.pm.api.projectdeclared.model.dto.ProjectRenewalDeclareExportDTO;
import com.hz.pm.api.projectdeclared.model.entity.PaymentPlan;
import com.hz.pm.api.projectdeclared.service.IPaymentPlanService;
import com.hz.pm.api.projectlib.model.enumeration.ProjectRenewalApprovalStatusEnum;
import com.hz.pm.api.projectlib.model.enumeration.ProjectStatusEnum;
import com.hz.pm.api.projectlib.model.enumeration.ProjectTypeNewEnum;
import com.hz.pm.api.projectlib.helper.ProjectRenewFundHelper;
import com.hz.pm.api.projectlib.model.dto.ProjectRenewalExportDTO;
import com.hz.pm.api.projectlib.model.dto.ProjectRenewalFundDeclarationDTO;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.model.entity.ProjectRenewalFundDeclaration;
import com.hz.pm.api.projectlib.model.po.ProjectRenewalFundDeclarationPO;
import com.hz.pm.api.projectlib.model.req.ProjectRenewalAuditReq;
import com.hz.pm.api.projectlib.model.req.ProjectRenewalListReq;
import com.hz.pm.api.projectlib.model.vo.AnnualAmountVO;
import com.hz.pm.api.projectlib.model.vo.ProjectLibListItemVO;
import com.hz.pm.api.projectlib.model.vo.ProjectRenewalFundDeclarationVO;
import com.hz.pm.api.projectlib.service.IProjectRenewalFundDeclarationService;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.user.security.model.UserFullInfoDTO;
import com.wflow.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * ProjectRenewalFundManage
 * </p>
 *
 * @author ZPF
 * @since 14:19 2023/2/15
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class ProjectRenewalFundManage {

    private final IProjectRenewalFundDeclarationService projectRenewalFundDeclarationService;

    private final IProjectService projectService;

    private final IGovBizProjectBaseinfoService baseinfoService;

    private final IGovOperationProjectBaseinfoService operationProjectBaseinfoService;

    private final IGovBizProjectApplyService applyService;

    private final IGovBizProjectApproveService approveService;

    private final RegionCacheHelper regionCacheHelper;

    private final IPaymentPlanService paymentPlanService;

    /**
     * 项目续建资金库列表 分页
     *
     * @param req
     * @return
     */
    public PageVo<ProjectRenewalFundDeclarationVO> list(ProjectRenewalListReq req, UserFullInfoDTO user) {
        Page<ProjectRenewalFundDeclarationPO> page = req.page();
        req = buildProjectLibPermission(req, user);
        projectRenewalFundDeclarationService.pageSql(page, req);
        long total;
        if ((total = page.getTotal()) == 0) {
            return PageVo.empty();
        }
        List<ProjectRenewalFundDeclarationVO> records = CollUtils.convert(page.getRecords(), w -> {
            ProjectRenewalFundDeclarationVO item = new ProjectRenewalFundDeclarationVO();
            BeanUtils.copyProperties(w, item);
            return item;
        });
        return PageVo.of(records, total);
    }

    public PageVo<ProjectLibListItemVO> projectList(ProjectRenewalListReq req) {
        UserInfoDetails user = LoginUserUtil.loginUserDetail();
        LambdaQueryWrapper<Project> query = ProjectRenewFundHelper.projectQuery(req);
        //项目查最新
        query.eq(Project::getNewest, Boolean.TRUE);
        //自己单位
        query.eq(Project::getBuildOrgCode, user.getMhUnitIdStr());
        //立项批复后 都可以
        query.gt(Project::getStatus, ProjectStatusEnum.APPROVED_AFTER_CHOICE.getCode());
        Page<Project> page = projectService.page(req.page(), query);
        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.empty();
        }

        List<String> projectCodes = CollUtils.fieldList(page.getRecords(), Project::getProjectCode);

        Map<Long, List<ProjectRenewalFundDeclaration>> renewalMap;
        if (CollUtil.isNotEmpty(projectCodes)) {
            Wrapper<ProjectRenewalFundDeclaration> prfQuery = Wrappers.lambdaQuery(ProjectRenewalFundDeclaration.class)
                    .in(ProjectRenewalFundDeclaration::getProjectCode, projectCodes)
                    .eq(ProjectRenewalFundDeclaration::getApprovalStatus, ProjectRenewalApprovalStatusEnum.PASS.name())
                    .eq(ProjectRenewalFundDeclaration::getDeleted, Boolean.FALSE)
                    .orderByAsc(ProjectRenewalFundDeclaration::getProjectYear);
            List<ProjectRenewalFundDeclaration> renewalDeclarations = projectRenewalFundDeclarationService.list(prfQuery);
            renewalMap = CollUtils.group(renewalDeclarations, ProjectRenewalFundDeclaration::getProjectId);
        } else {
            renewalMap = Collections.emptyMap();
        }

        Map<Long, List<ProjectRenewalFundDeclaration>> finalRenewalMap = renewalMap;
        List<ProjectLibListItemVO> records = CollUtils.convert(page.getRecords(), w -> {
            ProjectLibListItemVO item = new ProjectLibListItemVO();
            item.setId(w.getId());
            item.setProjectName(w.getProjectName());
            item.setProjectCode(w.getProjectCode());
            item.setArea(w.getArea());
            item.setAreaCode(w.getAreaCode());
            item.setCreateOn(w.getCreateOn());
            item.setDeclaredAmount(w.getDeclareAmount());
            item.setStage(w.getStage());
            item.setStatus(w.getStatus());
            item.setProjectType(w.getProjectType());
            item.setProjectYear(w.getProjectYear());
            item.setBuildOrg(w.getBuildOrgName());
            item.setBizDomain(w.getBizDomain());
            item.setProcessStatus(w.getProcessStatus());
            item.setInstCode(w.getInstCode());
            item.setIsHigherSuperOrg(w.getIsHigherSuperOrg());
            if (user.getIsOrgAdmin() &&
                    ProjectStatusEnum.PENDING_PREQUALIFICATION.eq(item.getStatus())
                    && StringUtils.isNotBlank(w.getSuperOrgCode())
                    && w.getSuperOrgCode().equals(user.getMhUnitIdStr())) {
                item.setCanPreDeclared(Boolean.TRUE);
            }
            item.setApprovedAmount(w.getApprovalAmount());
            item.setAnnualPlanAmount(w.getAnnualPlanAmount());
            item.setPrePlanProjectId(w.getPrePlanProjectId());
            if (finalRenewalMap.containsKey(item.getId())) {
                List<ProjectRenewalFundDeclaration> prfs = finalRenewalMap.get(item.getId());
                item.setAnnualAccumulateAmount(ProjectLibManage.computeAmount(w.getAnnualPlanAmount(), prfs));
                item.setAnnualAccumulateAmountList(ProjectLibManage.convertAccmulate(w, prfs));
            } else {
                item.setAnnualAccumulateAmount(w.getAnnualPlanAmount());
                item.setAnnualAccumulateAmountList(ProjectLibManage.convertAccmulate(w, Collections.emptyList()));
            }
            return item;
        });
        return PageVo.of(records, page.getTotal());
    }

    /**
     * @param id
     * @author ZPF
     * @since 2023/02/15 11:15
     */
    public ProjectRenewalFundDeclarationVO detail(Long id) {
        // 查询项目申报信息
        ProjectRenewalFundDeclaration renewal = projectRenewalFundDeclarationService.getById(id);
        if (Objects.isNull(renewal)) {
            return null;
        }
        ProjectRenewalFundDeclarationVO vo = new ProjectRenewalFundDeclarationVO();
        BeanUtils.copyProperties(renewal, vo);
        // 查询项目信息
        Project project = projectService.getProjectByCode(renewal.getProjectCode());
        GovBizProjectBaseinfo baseinfo = baseinfoService.getOne(Wrappers.lambdaQuery(GovBizProjectBaseinfo.class)
                .eq(GovBizProjectBaseinfo::getBaseProjId, renewal.getProjectCode())
                .last(BizConst.LIMIT_1));
        GovOperationProjectBaseinfo operationBaseinfo = operationProjectBaseinfoService.getOne(Wrappers.lambdaQuery(GovOperationProjectBaseinfo.class)
                .eq(GovOperationProjectBaseinfo::getBaseProjId, renewal.getProjectCode())
                .last(BizConst.LIMIT_1));
        GovBizProjectApply apply = applyService.getOne(Wrappers.lambdaQuery(GovBizProjectApply.class)
                .eq(GovBizProjectApply::getBaseProjId, renewal.getProjectCode())
                .last(BizConst.LIMIT_1));
        GovBizProjectApprove approve = approveService.getOne(Wrappers.lambdaQuery(GovBizProjectApprove.class)
                .eq(GovBizProjectApprove::getBaseProjId, renewal.getProjectCode())
                .last(BizConst.LIMIT_1));
        if (Objects.nonNull(project)) {
            vo.setApprovalAmount(project.getApprovalAmount());
            vo.setProjectName(project.getProjectName());
            vo.setProjectType(project.getProjectType());
            vo.setStage(project.getStage());
            vo.setStatus(project.getStatus());
            vo.setBuildOrgName(project.getBuildOrgName());
            vo.setAnnualPaymentAmount(renewal.getAnnualPaymentAmount());
            List<AnnualAmountVO> annualAmounts = Lists.newArrayList();
            annualAmounts.add(AnnualAmountVO.builder()
                    .projectId(project.getId())
                    .projectCode(project.getProjectCode())
                    .projectYear(project.getProjectYear())
                    .annualAmount(project.getAnnualPlanAmount())
                    .build());
            List<ProjectRenewalFundDeclaration> renewalDeclarations = projectRenewalFundDeclarationService.list(Wrappers.lambdaQuery(ProjectRenewalFundDeclaration.class)
                    .eq(ProjectRenewalFundDeclaration::getProjectId, vo.getProjectId())
                    .eq(ProjectRenewalFundDeclaration::getApprovalStatus, ProjectRenewalApprovalStatusEnum.PASS.name())
                    .eq(ProjectRenewalFundDeclaration::getDeleted, Boolean.FALSE)
                    .orderByAsc(ProjectRenewalFundDeclaration::getProjectYear));
            Optional.ofNullable(renewalDeclarations).ifPresent(declarations ->
                    declarations.forEach(declaration -> annualAmounts.add(AnnualAmountVO.builder()
                            .projectId(project.getId())
                            .projectCode(project.getProjectCode())
                            .projectYear(declaration.getProjectYear())
                            .annualAmount(declaration.getAnnualPaymentAmount())
                            .haveAmount(declaration.getHaveAmount())
                            .govOwnFinanceAmount(declaration.getGovOwnFinanceAmount())
                            .bankLendingAmount(declaration.getBankLendingAmount())
                            .govSuperiorFinanceAmount(declaration.getGovSuperiorFinanceAmount())
                            .otherAmount(declaration.getOtherAmount())
                            .build()))
            );
            vo.setAnnualAccumulateAmountList(annualAmounts);
        } else if (Objects.nonNull(baseinfo)) {
            if (Objects.nonNull(approve)) {
                vo.setApprovalAmount(approve.getBaseInitialReviewTotalMoney());
            }
            vo.setProjectName(baseinfo.getBaseProjName());
            vo.setProjectType(baseinfo.getBaseProjType());
            vo.setStatus(StringUtils.isNotBlank(baseinfo.getBaseProjSetProg()) ?
                    Integer.parseInt(baseinfo.getBaseProjSetProg()) : null);
            vo.setBuildOrgName(baseinfo.getBaseBuildDeprt());
            vo.setAnnualPaymentAmount(renewal.getAnnualPaymentAmount());
            List<AnnualAmountVO> annualAmounts = Lists.newArrayList();
            annualAmounts.add(AnnualAmountVO.builder()
                    .projectId(baseinfo.getId())
                    .projectCode(baseinfo.getBaseProjId())
                    .projectYear(StringUtils.isNotBlank(apply.getBaseProjSetYear()) ? Integer.parseInt(apply.getBaseProjSetYear()) : null)
                    .annualAmount(apply.getBaseProjDeclAmount())
                    .build());
            List<ProjectRenewalFundDeclaration> renewalDeclarations = projectRenewalFundDeclarationService.list(Wrappers.lambdaQuery(ProjectRenewalFundDeclaration.class)
                    .eq(ProjectRenewalFundDeclaration::getProjectCode, vo.getProjectCode())
                    .eq(ProjectRenewalFundDeclaration::getApprovalStatus, ProjectRenewalApprovalStatusEnum.PASS.name())
                    .eq(ProjectRenewalFundDeclaration::getDeleted, Boolean.FALSE)
                    .orderByAsc(ProjectRenewalFundDeclaration::getProjectYear));
            Optional.ofNullable(renewalDeclarations).ifPresent(declarations ->
                    declarations.forEach(declaration -> annualAmounts.add(AnnualAmountVO.builder()
                            .projectId(baseinfo.getId())
                            .projectCode(baseinfo.getBaseProjId())
                            .projectYear(declaration.getProjectYear())
                            .annualAmount(declaration.getAnnualPaymentAmount())
                            .haveAmount(declaration.getHaveAmount())
                            .govOwnFinanceAmount(declaration.getGovOwnFinanceAmount())
                            .bankLendingAmount(declaration.getBankLendingAmount())
                            .govSuperiorFinanceAmount(declaration.getGovSuperiorFinanceAmount())
                            .otherAmount(declaration.getOtherAmount())
                            .build()))
            );
            vo.setAnnualAccumulateAmountList(annualAmounts);
        } else if (Objects.nonNull(operationBaseinfo)) {
            if (Objects.nonNull(approve)) {
                vo.setApprovalAmount(approve.getBaseInitialReviewTotalMoney());
            }
            vo.setProjectName(operationBaseinfo.getBaseProjName());
            vo.setProjectType(operationBaseinfo.getBaseProjType());
            vo.setStatus(StringUtils.isNotBlank(operationBaseinfo.getBaseProjSetProg()) ?
                    Integer.parseInt(operationBaseinfo.getBaseProjSetProg()) : null);
            vo.setBuildOrgName(operationBaseinfo.getBaseBuildDeprt());
            vo.setAnnualPaymentAmount(renewal.getAnnualPaymentAmount());
            List<AnnualAmountVO> annualAmounts = Lists.newArrayList();
            annualAmounts.add(AnnualAmountVO.builder()
                    .projectId(operationBaseinfo.getId())
                    .projectCode(operationBaseinfo.getBaseProjId())
                    .projectYear(StrUtil.isNotBlank(apply.getBaseProjSetYear()) ? Integer.parseInt(apply.getBaseProjSetYear()) : null)
                    .annualAmount(apply.getBaseProjDeclAmount())
                    .build());
            List<ProjectRenewalFundDeclaration> renewalDeclarations = projectRenewalFundDeclarationService.list(Wrappers.lambdaQuery(ProjectRenewalFundDeclaration.class)
                    .eq(ProjectRenewalFundDeclaration::getProjectCode, vo.getProjectCode())
                    .eq(ProjectRenewalFundDeclaration::getApprovalStatus, ProjectRenewalApprovalStatusEnum.PASS.name())
                    .eq(ProjectRenewalFundDeclaration::getDeleted, Boolean.FALSE)
                    .orderByAsc(ProjectRenewalFundDeclaration::getProjectYear));
            Optional.ofNullable(renewalDeclarations).ifPresent(declarations ->
                    declarations.forEach(declaration -> annualAmounts.add(AnnualAmountVO.builder()
                            .projectId(operationBaseinfo.getId())
                            .projectCode(operationBaseinfo.getBaseProjId())
                            .projectYear(declaration.getProjectYear())
                            .annualAmount(declaration.getAnnualPaymentAmount())
                            .haveAmount(declaration.getHaveAmount())
                            .govOwnFinanceAmount(declaration.getGovOwnFinanceAmount())
                            .bankLendingAmount(declaration.getBankLendingAmount())
                            .govSuperiorFinanceAmount(declaration.getGovSuperiorFinanceAmount())
                            .otherAmount(declaration.getOtherAmount())
                            .build()))
            );
            vo.setAnnualAccumulateAmountList(annualAmounts);
        }
        return vo;
    }

    /**
     * 申报
     *
     * @param dto
     * @return
     */
    public Long declared(ProjectRenewalFundDeclarationDTO dto) {
        //要判断 项目id 是否 以及状态是 已验收
        String projectCode = dto.getProjectCode();
        Project project = projectService.getProjectByCode(projectCode);
        GovBizProjectBaseinfo baseinfo = baseinfoService.getOne(Wrappers.lambdaQuery(GovBizProjectBaseinfo.class)
                .eq(GovBizProjectBaseinfo::getBaseProjId, projectCode)
                .last(BizConst.LIMIT_1));
        GovOperationProjectBaseinfo operationBaseinfo = operationProjectBaseinfoService.getOne(Wrappers.lambdaQuery(GovOperationProjectBaseinfo.class)
                .eq(GovOperationProjectBaseinfo::getBaseProjId, projectCode)
                .last(BizConst.LIMIT_1));
        GovBizProjectApply apply = applyService.getOne(Wrappers.lambdaQuery(GovBizProjectApply.class)
                .eq(GovBizProjectApply::getBaseProjId, projectCode)
                .last(BizConst.LIMIT_1));

        VUtils.isTrue(Objects.isNull(project) && Objects.isNull(baseinfo) && Objects.isNull(operationBaseinfo)).throwMessage(String.format("关联的项目【%s】不存在 提交失败!", projectCode));
        ProjectRenewalFundDeclaration declaration = new ProjectRenewalFundDeclaration();
        //如果是重新申报
        if (Objects.nonNull(dto.getId())) {
            ProjectRenewalFundDeclaration oldDeclaration = projectRenewalFundDeclarationService.getById(dto.getId());
            VUtils.isTrue(Objects.isNull(oldDeclaration)).throwMessage(String.format("重新申报失败 【%s】 该申报不存在!", dto.getId()));
            BeanUtils.copyProperties(oldDeclaration, declaration);
        } else {
            declaration.setCreateOn(LocalDateTime.now());
            declaration.setUpdateOn(LocalDateTime.now());
        }
        BeanUtils.copyProperties(dto, declaration);

        //有2个条件要判断 续建资金
        //1. 如果有审核中的 是不能继续申请的
        long pendingCount = projectRenewalFundDeclarationService.count(Wrappers.lambdaQuery(ProjectRenewalFundDeclaration.class)
                .eq(ProjectRenewalFundDeclaration::getProjectCode, projectCode)
                .eq(ProjectRenewalFundDeclaration::getApprovalStatus, ProjectRenewalApprovalStatusEnum.PENDING.name()));
        VUtils.isTrue(pendingCount > 0L).throwMessage("当前有在审核的续建项目 不能再申请了");

        //2.是要当前最新资金的下年度 才能申请
        VUtils.isTrue(Objects.isNull(dto.getProjectYear())).throwMessage("新建的续建项目信息 年度不能为空");
        ProjectRenewalFundDeclaration lastRenewalFund = projectRenewalFundDeclarationService.getOne(Wrappers.lambdaQuery(ProjectRenewalFundDeclaration.class)
                .eq(ProjectRenewalFundDeclaration::getProjectCode, projectCode)
                .eq(ProjectRenewalFundDeclaration::getApprovalStatus, ProjectRenewalApprovalStatusEnum.PASS.name())
                .orderByDesc(ProjectRenewalFundDeclaration::getProjectYear)
                .last(BizConst.LIMIT_1));
        //如果没有续建资金信息 就要比 当前项目的年度要大
        if (Objects.isNull(lastRenewalFund)) {
            if (Objects.nonNull(project)) {
                VUtils.isTrue(project.getProjectYear() >= dto.getProjectYear())
                        .throwMessage("续建资金年度错误!");
            } else if (Objects.nonNull(apply)) {
                VUtils.isTrue(StringUtils.isBlank(apply.getBaseProjSetYear()) ||
                                Integer.parseInt(apply.getBaseProjSetYear()) >= dto.getProjectYear())
                        .throwMessage("续建资金年度错误!");
            }
        } else {
            VUtils.isTrue(lastRenewalFund.getProjectYear() >= dto.getProjectYear())
                    .throwMessage("续建资金年度错误!");
        }

        declaration.setApprovalStatus(ProjectRenewalApprovalStatusEnum.PENDING.name());
        if (Objects.nonNull(project)) {
            declaration.setRegionCode(project.getAreaCode());
            declaration.setOrgCode(project.getBuildOrgCode());
        } else if (Objects.nonNull(baseinfo)) {
            declaration.setRegionCode(StringUtils.isNotBlank(baseinfo.getBaseAreaCode()) ? baseinfo.getBaseAreaCode().substring(0, 6) : StringUtils.EMPTY);
            declaration.setOrgCode(baseinfo.getBaseBuildDeprtDing());
        } else if (Objects.nonNull(operationBaseinfo)) {
            declaration.setRegionCode(StringUtils.isNotBlank(operationBaseinfo.getBaseAreaCode()) ? operationBaseinfo.getBaseAreaCode().substring(0, 6) : StringUtils.EMPTY);
            declaration.setOrgCode(operationBaseinfo.getBaseBuildDeprtDing());
        }

        if (!projectRenewalFundDeclarationService.saveOrUpdate(declaration)) {
            throw new BusinessException(String.format("申报失败 【%s】", dto.getId()));
        }
        return declaration.getId();
    }

    //判断金额
    private void checkPaymentAmount(String projectCode, Integer projectYear, BigDecimal annualPlanAmount) {
        //判断金额问题
        //1 是否有该年度的合同支付计划
        List<PaymentPlan> paymentPlans = paymentPlanService.list(Wrappers.lambdaQuery(PaymentPlan.class)
                .eq(PaymentPlan::getProjectCode, projectCode)
                .orderByAsc(PaymentPlan::getPaymentTime));
        VUtils.isTrue(CollUtil.isEmpty(paymentPlans)).throwMessage("未有所选年度的支付计划，无法提交");
        boolean hasYearPlan = Boolean.FALSE;

        for (PaymentPlan plan : paymentPlans) {
            if (Objects.isNull(plan.getPaymentTime())) {
                continue;
            }
            int year = plan.getPaymentTime().getYear();
            if (projectYear.equals(year)) {
                hasYearPlan = Boolean.TRUE;
            } else if (projectYear.compareTo(year) > 0) {
                //2 如果有 这一年前的实际支付金额有没有填
                VUtils.isTrue(Objects.isNull(plan.getActualPaymentAmount()))
                        .throwMessage("有漏填写此年度之前年度的实际支付金额，请去合同备案补充");
            }
        }
        VUtils.isTrue(!hasYearPlan).throwMessage("未有所选年度的支付计划，无法提交");

        //3. 算出 所能申报的最大金额
        //3.1 算出 申报年 以及 之前的所有合同计划金额
        BigDecimal planSum = BigDecimal.ZERO;
        Optional<BigDecimal> planSumOp = paymentPlans.stream().filter(c -> Objects.nonNull(c.getPaymentTime()) &&
                        (c.getPaymentTime().getYear() - projectYear) <= 0)
                .map(c -> Objects.nonNull(c.getPaymentAmount()) ? c.getPaymentAmount() : BigDecimal.ZERO)
                .reduce(BigDecimal::add);
        if (planSumOp.isPresent()) {
            planSum = planSumOp.get();
        }
        BigDecimal actualPlanSum = BigDecimal.ZERO;
        Optional<BigDecimal> actualPlanSumOp = paymentPlans.stream().filter(c -> Objects.nonNull(c.getPaymentTime()) &&
                        (c.getPaymentTime().getYear() - projectYear) < 0)
                .map(c -> Objects.nonNull(c.getActualPaymentAmount()) ? c.getActualPaymentAmount() : BigDecimal.ZERO)
                .reduce(BigDecimal::add);
        if (actualPlanSumOp.isPresent()) {
            actualPlanSum = actualPlanSumOp.get();
        }
        BigDecimal maxAmount = planSum.subtract(actualPlanSum);
        VUtils.isTrue(annualPlanAmount.compareTo(maxAmount) > 0).throwMessage("所填年度支付金额 超出 最大限额");
    }


    /**
     * 续建项目审核
     *
     * @param param
     * @return
     */
    public Long audit(ProjectRenewalAuditReq param) {
        Long projectRenewalId = param.getProjectRenewalId();
        ProjectRenewalFundDeclaration projectRenewal = projectRenewalFundDeclarationService.getById(projectRenewalId);
        VUtils.isTrue(Objects.isNull(projectRenewal)).throwMessage("该续建信息不存在!");
        Project project = projectService.getProjectByCode(projectRenewal.getProjectCode());
        GovBizProjectBaseinfo baseinfo = baseinfoService.getOne(Wrappers.lambdaQuery(GovBizProjectBaseinfo.class)
                .eq(GovBizProjectBaseinfo::getBaseProjId, projectRenewal.getProjectCode())
                .last(BizConst.LIMIT_1));
        GovOperationProjectBaseinfo operationBaseinfo = operationProjectBaseinfoService.getOne(Wrappers.lambdaQuery(GovOperationProjectBaseinfo.class)
                .eq(GovOperationProjectBaseinfo::getBaseProjId, projectRenewal.getProjectCode())
                .last(BizConst.LIMIT_1));
        VUtils.isTrue(Objects.isNull(project) && Objects.isNull(baseinfo) && Objects.isNull(operationBaseinfo)).throwMessage("关联的项目已经被删除!");
        if (Boolean.TRUE.equals(param.getResult())) {
            projectRenewal.setApprovalStatus(ProjectRenewalApprovalStatusEnum.PASS.name());
        } else {
            String auditOpinion = param.getAuditOpinion();
            if (StrUtil.isBlank(auditOpinion)) {
                throw new BizException("审核意见不能为空");
            }
            projectRenewal.setAuditOpinion(auditOpinion);
            projectRenewal.setApprovalStatus(ProjectRenewalApprovalStatusEnum.NOT_PASS.name());
        }
        if (Objects.nonNull(project)) {
            projectRenewal.setRegionCode(project.getAreaCode());
            projectRenewal.setOrgCode(project.getBuildOrgCode());
        } else if (Objects.nonNull(baseinfo)) {
            projectRenewal.setRegionCode(StringUtils.isNotBlank(baseinfo.getBaseAreaCode()) ? baseinfo.getBaseAreaCode().substring(0, 6) : StringUtils.EMPTY);
            projectRenewal.setOrgCode(baseinfo.getBaseBuildDeprtDing());
        } else if (Objects.nonNull(operationBaseinfo)) {
            projectRenewal.setRegionCode(StringUtils.isNotBlank(operationBaseinfo.getBaseAreaCode()) ? operationBaseinfo.getBaseAreaCode().substring(0, 6) : StringUtils.EMPTY);
            projectRenewal.setOrgCode(operationBaseinfo.getBaseBuildDeprtDing());
        }
        projectRenewal.setAuditOpinion(param.getAuditOpinion());
        projectRenewal.setUpdateOn(LocalDateTime.now());
        projectRenewalFundDeclarationService.updateById(projectRenewal);
        return projectRenewal.getId();
    }

    /**
     * 续建项目删除
     *
     * @param projectRenewalId
     * @return
     */
    public Long delete(Long projectRenewalId) {
        ProjectRenewalFundDeclaration projectRenewal = projectRenewalFundDeclarationService.getById(projectRenewalId);
        projectRenewal.setDeleted(true);
        projectRenewal.setUpdateOn(LocalDateTime.now());
        projectRenewalFundDeclarationService.updateById(projectRenewal);
        return projectRenewal.getId();
    }

    public void exportList(HttpServletResponse response, ProjectRenewalListReq param) {

        param.setPageNumber(CommonConst.EXPORT_PAGE_NUMBER);
        param.setPageSize(CommonConst.EXPORT_PAGE_SIZE);
        Page<ProjectRenewalFundDeclarationPO> page = param.page();
        projectRenewalFundDeclarationService.pageSql(page, param);
        List<ProjectRenewalFundDeclarationPO> records = page.getRecords();

        List<ProjectRenewalExportDTO> collect = records.stream().map(r -> {
            ProjectRenewalExportDTO exportDTO = new ProjectRenewalExportDTO();
            BeanUtils.copyProperties(r, exportDTO);
            exportDTO.setProjectTypeName(ProjectTypeNewEnum.getDesc(r.getProjectType()));
            if (ProjectRenewalApprovalStatusEnum.PENDING.name().equals(r.getApprovalStatus())) {
                exportDTO.setApprovalStatusName(ProjectRenewalApprovalStatusEnum.PENDING.getDesc());
            } else if (ProjectRenewalApprovalStatusEnum.PASS.name().equals(r.getApprovalStatus())) {
                exportDTO.setApprovalStatusName(ProjectRenewalApprovalStatusEnum.PASS.getDesc());
            } else if (ProjectRenewalApprovalStatusEnum.NOT_PASS.name().equals(r.getApprovalStatus())) {
                exportDTO.setApprovalStatusName(ProjectRenewalApprovalStatusEnum.NOT_PASS.getDesc());
            }
            String createOnStr = NdDateUtils.format(r.getCreateOn(), "yyyy-MM-dd HH:mm");
            exportDTO.setCreateOn(createOnStr);
            return exportDTO;
        }).collect(Collectors.toList());

        for (int i = 0; i < collect.size(); i++) {
            collect.get(i).setSerialNumber(i + 1);
        }


        String fileName = "续建项目资金库列表";
        ExcelDownUtil.setFileName(fileName, response);
        //数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), ProjectRenewalExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new BizException(e);
        }
    }

    public void exportRenewalDeclareList(HttpServletResponse response, ProjectRenewalListReq param) {
        param.setPageNumber(CommonConst.EXPORT_PAGE_NUMBER);
        param.setPageSize(CommonConst.EXPORT_PAGE_SIZE);
        Page<ProjectRenewalFundDeclarationPO> page = param.page();
        projectRenewalFundDeclarationService.pageSql(page, param);
        List<ProjectRenewalFundDeclarationPO> records = page.getRecords();

        List<ProjectRenewalDeclareExportDTO> collect = records.stream().map(r -> {
            ProjectRenewalDeclareExportDTO exportDTO = new ProjectRenewalDeclareExportDTO();
            BeanUtils.copyProperties(r, exportDTO);
            exportDTO.setProjectTypeName(ProjectTypeNewEnum.getDesc(r.getProjectType()));
            if (ProjectRenewalApprovalStatusEnum.PENDING.name().equals(r.getApprovalStatus())) {
                exportDTO.setApprovalStatusName(ProjectRenewalApprovalStatusEnum.PENDING.getDesc());
            } else if (ProjectRenewalApprovalStatusEnum.PASS.name().equals(r.getApprovalStatus())) {
                exportDTO.setApprovalStatusName(ProjectRenewalApprovalStatusEnum.PASS.getDesc());
            } else if (ProjectRenewalApprovalStatusEnum.NOT_PASS.name().equals(r.getApprovalStatus())) {
                exportDTO.setApprovalStatusName(ProjectRenewalApprovalStatusEnum.NOT_PASS.getDesc());
            }
            String createOnStr = NdDateUtils.format(r.getCreateOn(), "yyyy-MM-dd HH:mm");
            exportDTO.setCreateOn(createOnStr);
            return exportDTO;
        }).collect(Collectors.toList());

        for (int i = 0; i < collect.size(); i++) {
            collect.get(i).setSerialNumber(i + 1);
        }

        String fileName = "续建项目资金申报列表";
        ExcelDownUtil.setFileName(fileName, response);
        //数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), ProjectRenewalDeclareExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new BizException(e);
        }
    }

    public ProjectRenewalListReq buildProjectLibPermission(ProjectRenewalListReq req, UserFullInfoDTO user) {
        Optional<DataScopeDTO> currentUserDataScope = DataScopeUtil.getCurrentUserDataScope(user);
        if (!currentUserDataScope.isPresent()) {
            log.warn("没有取到权限信息 当前查询 没有权限条件");
            return req;
        }

        switch (currentUserDataScope.get().getRole()) {
            case NORMAL_MEMBER:
                //普通用户 只能看到自己单位去申报的
                req.setUserType("normal");
                req.setUserValue(user.getMhUnitIdStr());
                break;
            case COMPANY_MANAGER:
            case SUPER_ADMIN:
            case REGION_MANAGER:
                //单位管理员 看到自己单位去申报的 + 待预审的主管单位是自己单位的项目
                //超级管理员 也只能看本单位的
                req.setUserType("org");
                req.setUserValue(user.getMhUnitIdStr());
                break;
            case VISITOR:
                //访客可以看全市的
                break;
            case DASHBOARD:
                break;
            default:
                //没有权限的话 就让它查不到
                req.setId(0L);
                break;
        }
        return req;
    }
}
