package com.ecep.contract.task;

import java.io.File;
import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;

import org.springframework.util.StringUtils;

import com.ecep.contract.CompanyCustomerFileType;
import com.ecep.contract.ContractFileType;
import com.ecep.contract.ContractPayWay;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.MyDateTimeUtils;
import com.ecep.contract.SpringApp;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.model.CompanyExtendInfo;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractBidVendor;
import com.ecep.contract.model.ContractFile;
import com.ecep.contract.model.ContractFileTypeLocal;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.ExtendVendorInfo;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectBid;
import com.ecep.contract.model.ProjectCost;
import com.ecep.contract.model.ProjectQuotation;
import com.ecep.contract.model.ProjectSaleType;
import com.ecep.contract.model.ProjectSaleTypeRequireFileType;
import com.ecep.contract.model.VendorGroup;
import com.ecep.contract.model.VendorGroupRequireFileType;
import com.ecep.contract.service.CompanyCustomerFileService;
import com.ecep.contract.service.CompanyCustomerService;
import com.ecep.contract.service.CompanyExtendInfoService;
import com.ecep.contract.service.CompanyFileService;
import com.ecep.contract.service.CompanyService;
import com.ecep.contract.service.CompanyVendorService;
import com.ecep.contract.service.ContractBidVendorService;
import com.ecep.contract.service.ContractFileService;
import com.ecep.contract.service.ContractFileTypeService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.EmployeeService;
import com.ecep.contract.service.ExtendVendorInfoService;
import com.ecep.contract.service.ProjectBidService;
import com.ecep.contract.service.ProjectCostService;
import com.ecep.contract.service.ProjectQuotationService;
import com.ecep.contract.service.ProjectSaleTypeRequireFileTypeService;
import com.ecep.contract.service.ProjectSaleTypeService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.service.VendorGroupRequireFileTypeService;
import com.ecep.contract.service.VendorGroupService;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableMap;
import javafx.util.converter.NumberStringConverter;
import lombok.Data;

@Data
public class ContractVerifyComm {
    // Project
    private ProjectService projectService;
    private ProjectSaleTypeRequireFileTypeService saleTypeRequireFileTypeService;
    private ProjectSaleTypeService saleTypeService;
    private ProjectCostService projectCostService;
    private ProjectQuotationService projectQuotationService;
    private ProjectBidService projectBidService;
    // Contract
    private ContractService contractService;
    private ContractFileService contractFileService;
    private ContractFileTypeService contractFileTypeService;
    private ContractBidVendorService contractBidVendorService;

    // Company
    private CompanyService companyService;
    private CompanyFileService companyFileService;
    // Vendor
    private CompanyVendorService companyVendorService;
    private VendorGroupService vendorGroupService;
    private VendorGroupRequireFileTypeService vendorGroupRequireFileTypeService;
    private ExtendVendorInfoService extendVendorInfoService;
    // Customer
    private CompanyCustomerService companyCustomerService;
    private CompanyCustomerFileService companyCustomerFileService;
    private CompanyExtendInfoService companyExtendInfoService;
    // Employee
    private EmployeeService employeeService;

    private ProjectService getProjectService() {
        if (projectService == null) {
            projectService = SpringApp.getBean(ProjectService.class);
        }
        return projectService;
    }

    private ProjectSaleTypeService getSaleTypeService() {
        if (saleTypeService == null) {
            saleTypeService = SpringApp.getBean(ProjectSaleTypeService.class);
        }
        return saleTypeService;
    }

    ProjectCostService getProjectCostService() {
        if (projectCostService == null) {
            projectCostService = SpringApp.getBean(ProjectCostService.class);
        }
        return projectCostService;
    }

    ProjectQuotationService getProjectQuotationService() {
        if (projectQuotationService == null) {
            projectQuotationService = SpringApp.getBean(ProjectQuotationService.class);
        }
        return projectQuotationService;
    }

    ProjectBidService getProjectBidService() {
        if (projectBidService == null) {
            projectBidService = SpringApp.getBean(ProjectBidService.class);
        }
        return projectBidService;
    }

    private ProjectSaleTypeRequireFileTypeService getSaleTypeRequireFileTypeService() {
        if (saleTypeRequireFileTypeService == null) {
            saleTypeRequireFileTypeService = SpringApp.getBean(ProjectSaleTypeRequireFileTypeService.class);
        }
        return saleTypeRequireFileTypeService;
    }

    public ContractService getContractService() {
        if (contractService == null) {
            contractService = SpringApp.getBean(ContractService.class);
        }
        return contractService;
    }

    private ContractFileService getContractFileService() {
        if (contractFileService == null) {
            contractFileService = SpringApp.getBean(ContractFileService.class);
        }
        return contractFileService;
    }

    private ContractFileTypeService getContractFileTypeService() {
        if (contractFileTypeService == null) {
            contractFileTypeService = SpringApp.getBean(ContractFileTypeService.class);
        }
        return contractFileTypeService;
    }

    private ContractBidVendorService getContractBidVendorService() {
        if (contractBidVendorService == null) {
            contractBidVendorService = SpringApp.getBean(ContractBidVendorService.class);
        }
        return contractBidVendorService;
    }

    private CompanyService getCompanyService() {
        if (companyService == null) {
            companyService = SpringApp.getBean(CompanyService.class);
        }
        return companyService;
    }

    private CompanyFileService getCompanyFileService() {
        if (companyFileService == null) {
            companyFileService = SpringApp.getBean(CompanyFileService.class);
        }
        return companyFileService;
    }

    private VendorGroupService getVendorGroupService() {
        if (vendorGroupService == null) {
            vendorGroupService = SpringApp.getBean(VendorGroupService.class);
        }
        return vendorGroupService;
    }

    private VendorGroupRequireFileTypeService getVendorGroupRequireFileTypeService() {
        if (vendorGroupRequireFileTypeService == null) {
            vendorGroupRequireFileTypeService = SpringApp.getBean(VendorGroupRequireFileTypeService.class);
        }
        return vendorGroupRequireFileTypeService;
    }

    private ExtendVendorInfoService getExtendVendorInfoService() {
        if (extendVendorInfoService == null) {
            extendVendorInfoService = SpringApp.getBean(ExtendVendorInfoService.class);
        }
        return extendVendorInfoService;
    }

    private CompanyVendorService getCompanyVendorService() {
        if (companyVendorService == null) {
            companyVendorService = SpringApp.getBean(CompanyVendorService.class);
        }
        return companyVendorService;
    }

    private CompanyCustomerService getCompanyCustomerService() {
        if (companyCustomerService == null) {
            companyCustomerService = SpringApp.getBean(CompanyCustomerService.class);
        }
        return companyCustomerService;
    }

    private CompanyCustomerFileService getCompanyCustomerFileService() {
        if (companyCustomerFileService == null) {
            companyCustomerFileService = SpringApp.getBean(CompanyCustomerFileService.class);
        }
        return companyCustomerFileService;
    }

    private CompanyExtendInfoService getCompanyExtendInfoService() {
        if (companyExtendInfoService == null) {
            companyExtendInfoService = SpringApp.getBean(CompanyExtendInfoService.class);
        }
        return companyExtendInfoService;
    }

    private EmployeeService getEmployeeService() {
        if (employeeService == null) {
            employeeService = SpringApp.getBean(EmployeeService.class);
        }
        return employeeService;
    }

    /**
     *
     */
    private ObservableMap<ContractFileType, ContractFileTypeLocal> fileTypeLocalMap = null;
    private Locale locale = Locale.getDefault();
    private Contract contract;

    /**
     * 是否验证企业存储目录
     */
    private SimpleBooleanProperty verifyCompanyPath = new SimpleBooleanProperty(true);
    /**
     * 是否验证企业状态
     */
    private SimpleBooleanProperty verifyCompanyStatus = new SimpleBooleanProperty(true);
    /**
     * 是否验证企业文件(资信报告)
     */
    private SimpleBooleanProperty verifyCompanyCredit = new SimpleBooleanProperty(true);
    /**
     * 是否验证客户
     */
    private SimpleBooleanProperty verifyCustomer = new SimpleBooleanProperty(true);
    /**
     * 是否验证客户文件(合同文件)
     */
    private SimpleBooleanProperty verifyCustomerFiles = new SimpleBooleanProperty(true);
    /**
     * 是否验证客户子合同日期
     */
    private SimpleBooleanProperty verifyCustomerSubContractDate = new SimpleBooleanProperty(true);
    /**
     * 是否验证供应商
     */
    private SimpleBooleanProperty verifyVendor = new SimpleBooleanProperty(true);
    /**
     * 是否验证供应商文件(供应商合同)
     */
    private SimpleBooleanProperty verifyVendorFiles = new SimpleBooleanProperty(true);

    /**
     * 合同合规性检测
     *
     * @param contract 要验证的合同对象
     * @param holder   输出
     */
    public void verify(Contract contract, MessageHolder holder) {
        LocalDate setupDate = contract.getSetupDate();
        if (setupDate == null) {
            holder.error("未设置合同提交日期");
            return;
        }

        Company company = contract.getCompany();
        if (company == null) {
            holder.error("未关联企业");
            return;
        }
        company = getCompanyService().findById(company.getId());
        verify(company, contract, holder);
    }

    public void verify(Company company, Contract contract, MessageHolder holder) {
        LocalDate setupDate = contract.getSetupDate();

        Employee employee = contract.getEmployee();
        if (employee == null) {
            holder.error("未关联业务员");
        }

        if (contract.getAmount() == null || contract.getAmount() <= 0) {
            holder.error("合同金额小于等于0");
        }

        CompanyExtendInfo companyExtendInfo = getCompanyExtendInfoService().findByCompany(company);

        if (companyExtendInfo.isDisableVerify()) {
            holder.debug("公司设定不做校验");
        } else {
            if (verifyCompanyPath.get()) {
                if (!getCompanyService().existsCompanyPath(company)) {
                    holder.error("公司目录未设置");
                } else {
                    if (!getCompanyService().checkCompanyPathInBasePath(company)) {
                        holder.error("公司目录未在规定目录下");
                    }
                }
            }

            if (verifyCompanyStatus.get()) {
                getCompanyService().verifyEnterpriseStatus(company, setupDate, holder);
            }

            if (verifyCompanyCredit.get()) {
                getCompanyFileService().verify(company, contract.getSetupDate(), holder);
            }
        }

        // 合同类型
        switch (contract.getPayWay()) {
            case RECEIVE -> {
                // 销售合同
                verifyAsCustomer(company, companyExtendInfo, contract, holder);

                // 销售合同下的采购合同
                List<Contract> list = getContractService().findAllBySaleContract(contract);
                if (!list.isEmpty()) {
                    for (Contract v : list) {
                        MessageHolder subHolder = holder.sub(v.getCode() + " -> ");
                        subHolder.info("采购合同 ： " + v.getName());
                        verify(v, subHolder);
                        if (getContractService().existsContractPath(v)) {
                            if (!getContractService().checkContractPathInBasePath(v)) {
                                holder.error("合同目录未在规定目录下");
                            }
                        } else {
                            holder.error("合同目录未设置");
                        }
                    }

                    DoubleSummaryStatistics statistics = list.stream().mapToDouble(c -> {
                        return Objects.requireNonNullElse(c.getAmount(), 0.0);
                    }).summaryStatistics();
                    NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);

                    holder.debug("采购合同金额合计：" + numberFormat.format(statistics.getSum()));
                    holder.debug("采购合同金额平均值：" + numberFormat.format(statistics.getAverage()));
                    holder.debug("采购合同金额最大值：" + numberFormat.format(statistics.getMax()));
                    holder.debug("采购合同金额最小值：" + numberFormat.format(statistics.getMin()));
                    if (contract.getAmount() != null && statistics.getSum() > contract.getAmount()) {
                        holder.warn("采购合同金额合计大于销售合同金额");
                    }
                }

                break;
            }
            case PAY -> {
                verifyAsVendor(company, contract, holder);
                break;
            }
            case OTHER -> {
                holder.error("合同付款类型：其他");
                break;
            }
            default -> {
                holder.error("合同付款类型：未设置");
            }
        }
    }

    private void verifyAsVendor(Company company, Contract contract, MessageHolder holder) {
        // 供应商，检查评价表
        ExtendVendorInfo vendorInfo = getExtendVendorInfoService().findByContract(contract);
        if (vendorInfo == null) {
            ExtendVendorInfo info = getExtendVendorInfoService().newInstanceByContract(contract);
            vendorInfo = getExtendVendorInfoService().save(info);
            holder.info("创建供应商信息 #" + vendorInfo.getId());
        }
        VendorGroup group = vendorInfo.getGroup();
        boolean assignedProvider = vendorInfo.isAssignedProvider();
        if (assignedProvider) {
            holder.debug("采购信息中设定为指定供应商");
        }

        if (group != null) {
            group = getVendorGroupService().findById(group.getId());
            vendorInfo.setGroup(group);
        }
        if (verifyCustomerSubContractDate.get()) {
            // 检查子合同日期是否在销售合同之后
            if (!vendorInfo.isPrePurchase()) {
                String parentCode = contract.getParentCode();
                if (StringUtils.hasText(parentCode)) {
                    Contract parent = getContractService().findByCode(parentCode);
                    if (parent != null) {
                        if (contract.getSetupDate().isBefore(parent.getSetupDate())) {
                            holder.warn("采购合同：" + contract.getCode() + " 提交日期在销售合同之前");
                        }
                    }
                }
            }
        }
        if (verifyVendor.get()) {
            getCompanyVendorService().verify(contract, holder);
        }

        if (verifyVendorFiles.get()) {
            holder.debug("核验文件...");
            verifyVendorFile(group, assignedProvider, contract, holder);
        }
    }

    private void verifyVendorFile(VendorGroup group, boolean assignedProvider, Contract contract,
            MessageHolder holder) {
        if (group == null) {
            return;
        }
        boolean loseFile = false;
        List<ContractFile> files = getContractFileService().findAllByContract(contract);
        List<VendorGroupRequireFileType> list = getVendorGroupRequireFileTypeService().findByGroupId(group.getId());
        if (list != null && !list.isEmpty()) {
            for (VendorGroupRequireFileType item : list) {
                ContractFileType fileType = item.getFileType();
                if (fileType == null) {
                    continue;
                }
                if (fileType == ContractFileType.QuotationSheet && assignedProvider
                        && group.isRequireQuotationSheetForBid()) {
                    continue;
                }
                if (!hasFileType(files, fileType)) {
                    holder.error("供应商" + getFileTypeLocalValue(fileType) + "未上传");
                    loseFile = true;
                }

            }
        }

        // 供应商比价
        if (group.isPriceComparison()) {
            if (assignedProvider) {
                holder.debug("指定供应商, 跳过供应商比价");
            } else {
                boolean requireQuotation = group.isRequireQuotationSheetForBid();
                List<ContractBidVendor> bidVendors = getContractBidVendorService().findByContract(contract);
                if (bidVendors == null || bidVendors.isEmpty()) {
                    holder.error("未上报供应商比价");
                } else {
                    for (ContractBidVendor bidVendor : bidVendors) {
                        ContractFile contractFile = bidVendor.getQuotationSheet();
                        if (contractFile == null) {
                            if (requireQuotation && bidVendor.getCompany().equals(contract.getCompany())) {
                                holder.debug("供应商类型启用了允许选中供应商不必须要有报价表");
                            } else {
                                holder.error("供应商比价：" + bidVendor.getCompany().getName() + " 未上传/关联报价表");
                                loseFile = true;
                            }
                        } else {
                            contractFile = getContractFileService().findById(contractFile.getId());
                            ContractFileType type = contractFile.getType();
                            if (type != ContractFileType.QuotationSheet) {
                                holder.error("供应商比价：" + contractFile.getFileName() + " 报价表记录异常，类型错误");
                            }
                            File file = new File(contract.getPath(), contractFile.getFileName());
                            if (!file.exists()) {
                                holder.error("供应商比价：" + file.getName() + " 报价表记录异常，文件不存在");
                                loseFile = true;
                            }
                        }
                    }
                }
            }
        }
        if (loseFile && files.isEmpty()) {
            holder.warn("!上传文件空!");
        }
    }

    ContractFileTypeLocal getFileTypeLocal(ContractFileType type) {
        if (fileTypeLocalMap == null) {
            fileTypeLocalMap = FXCollections
                    .observableMap(getContractFileTypeService().findAll(getLocale()));
        }
        return fileTypeLocalMap.get(type);
    }

    String getFileTypeLocalValue(ContractFileType type) {
        ContractFileTypeLocal fileTypeLocal = getFileTypeLocal(type);
        if (fileTypeLocal == null) {
            return type.name();
        }
        return fileTypeLocal.getValue();
    }

    private boolean hasFileType(List<ContractFile> files, ContractFileType fileType) {
        if (files == null || files.isEmpty()) {
            return false;
        }
        for (ContractFile file : files) {
            if (file.getType() == fileType) {
                return true;
            }
        }
        return false;
    }

    private void verifyAsCustomer(Company company, CompanyExtendInfo companyExtendInfo, Contract contract,
            MessageHolder holder) {
        boolean valiad = true;
        Project project = contract.getProject();
        if (project == null) {
            // 收款的合同时，检查是否关联了项目，如果没有则创建
            if (contract.getPayWay() == ContractPayWay.RECEIVE) {
                project = getProjectService().findByCode(contract.getCode());
                if (project == null) {
                    holder.info("创建关联项目");
                    try {
                        project = getProjectService().newInstanceByContract(contract);
                        project = getProjectService().save(project);
                    } catch (Exception e) {
                        holder.error("创建关联项目失败: " + e.getMessage());
                        throw new RuntimeException("code=" + contract.getCode(), e);
                    }
                }
                contract.setProject(project);
                contract = getContractService().save(contract);
            }
        }
        if (project != null) {
            project = getProjectService().findById(project.getId());
            // fixed
            contract.setProject(project);
        }

        if (project != null) {
            holder.info("验证项目信息:" + project.getCode() + " " + project.getName());
            verifyProject(contract, project, holder.sub("项目"));

            ProjectSaleType saleType = project.getSaleType();
            if (saleType != null) {
                if (getContractService().existsContractPath(contract)) {
                    saleType = getSaleTypeService().findById(saleType.getId());
                    project.setSaleType(saleType);
                    if (!contract.getPath().startsWith(saleType.getPath())) {
                        holder.error("合同目录未在销售类型目录下");
                    }
                }
            }
        }

        if (!companyExtendInfo.isDisableVerify()) {
            if (!verifyCustomerContract(contract, holder)) {
                valiad = false;
            }

            if (verifyCustomerFiles.get()) {
                holder.debug("核验文件...");
                if (!verifyContractFileAsCustomer(project, contract, holder)) {
                    valiad = false;
                }
            }
        }
    }

    /**
     * 客户，检查评估表
     */
    private boolean verifyCustomerContract(Contract contract, MessageHolder holder) {
        if (!verifyCustomer.get()) {
            return false;
        }
        boolean valid = true;
        Company company = contract.getCompany();
        if (company == null) {
            holder.warn("合同未关联公司");
            valid = false;
        }

        CompanyCustomer companyCustomer = getCompanyCustomerService().findByCompany(company);
        if (companyCustomer == null) {
            holder.warn("合同未关联客户");
            valid = false;
        } else {
            if (!StringUtils.hasText(companyCustomer.getPath())) {
                holder.warn("客户未设置文件夹");
                valid = false;
            }
            LocalDate developDate = companyCustomer.getDevelopDate();
            if (developDate == null) {
                holder.warn("客户未设置开发日期");
                valid = false;
            }
            if (!verifyCustomerFileByContract(companyCustomer, contract, holder)) {
                valid = false;
            }
        }
        return valid;
    }

    private boolean verifyCustomerFileByContract(CompanyCustomer companyCustomer, Contract contract,
            MessageHolder holder) {
        List<LocalDate> verifyDates = new ArrayList<>();
        LocalDate minDate = LocalDate.of(2022, 1, 1);
        LocalDate developDate = companyCustomer.getDevelopDate();
        if (developDate != null) {
            if (developDate.isAfter(minDate)) {
                minDate = developDate;
            }
        }
        if (contract.getSetupDate() != null) {
            LocalDate setupDate = contract.getSetupDate();
            if (setupDate.isBefore(developDate)) {
                holder.error("合同提交日期 " + setupDate + " 早于客户开发日期 " + developDate + ".");
                return false;
            }
            if (setupDate.isBefore(minDate)) {
                holder.debug("合同提交日期 " + setupDate + " 早于 " + minDate + ", 跳过");
            } else {
                verifyDates.add(setupDate);
            }
        }
        if (contract.getStartDate() != null) {
            LocalDate startDate = contract.getStartDate();
            if (startDate.isBefore(developDate)) {
                holder.warn("合同起始日期 " + startDate + " 早于客户开发日期 " + developDate + ".");
            }

            if (startDate.isBefore(minDate)) {
                holder.debug("合同起始日期 " + startDate + " 早于 " + minDate + ", 跳过");
            } else {
                verifyDates.add(startDate);
            }
        }
        if (contract.getOrderDate() != null) {
            LocalDate orderDate = contract.getOrderDate();
            if (orderDate.isBefore(developDate)) {
                holder.error("合同签订日期 " + orderDate + " 早于客户开发日期 " + developDate + ".");
                return false;
            }
            if (orderDate.isBefore(minDate)) {
                holder.debug("合同签订日期 " + orderDate + " 早于 " + minDate + ", 跳过");
            } else {
                verifyDates.add(orderDate);
            }
        }

        if (verifyDates.isEmpty()) {
            holder.warn("合同没有符合可核验的日期");
            return false;
        }

        // 客户
        List<CompanyCustomerFile> files = getCompanyCustomerFileService().findAllByCustomer(companyCustomer);
        if (files == null || files.isEmpty()) {
            holder.warn("未见客户评估表");
            return false;
        }

        for (LocalDate verifyDate : verifyDates) {
            CompanyCustomerFile customerFile = files.stream()
                    .filter(v -> v.getSignDate() != null && v.isValid())
                    .filter(v -> v.getType() == CompanyCustomerFileType.EvaluationForm)
                    .filter(v -> MyDateTimeUtils.dateValidFilter(verifyDate, v.getSignDate(),
                            v.getSignDate().plusYears(1), 7))
                    .findFirst().orElse(null);
            if (customerFile != null) {
                return true;
            }
        }

        CompanyCustomerFile latestFile = files.stream()
                .filter(v -> v.getSignDate() != null && v.isValid())
                .filter(v -> v.getType() == CompanyCustomerFileType.EvaluationForm)
                .max(Comparator.comparing(CompanyCustomerFile::getSignDate))
                .orElse(null);

        if (latestFile == null) {
            holder.error("未匹配的客户评估");
            return false;
        }

        holder.error("客户评估已过期，最后一个客户评估报告日期：" + latestFile.getSignDate() + ", 检测日期："
                + verifyDates.stream().map(LocalDate::toString).collect(Collectors.joining(", ")));
        return false;
    }

    private void verifyProject(Contract contract, Project project, MessageHolder holder) {
        ProjectSaleType saleType = project.getSaleType();
        if (saleType == null) {
            String code = contract.getCode();
            if (code != null && code.length() > 5) {
                saleType = getSaleTypeService().findByCode(code.substring(0, 1));
            }
        }

        if (saleType == null) {
            holder.warn("销售类型未设置");
        }
        if (project.getAmount() == null || project.getAmount() <= 0) {
            holder.error("金额小于等于0");
        }

        //
        boolean needImport = false;

        ProjectCost autoCost = getProjectCostService().findAutoCostByProject(project);
        if (autoCost == null) {
            // 创建 V0 项目成本
            ProjectCost cost = getProjectCostService().newInstanceByProject(project);
            cost.setVersion(0);
            cost.setApplicant(getEmployeeService().findById(EmployeeService.DEFAULT_SYSTEM_EMPLOYEE_ID));
            cost.setApplyTime(LocalDateTime.now());
            cost.setDescription("自动导入");
            autoCost = getProjectCostService().save(cost);
            needImport = true;
        } else {
            // 检查 V0 项目成本
            if (autoCost.getGrossProfitMargin() <= 0) {
                NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
                instance.setMaximumFractionDigits(2);
                NumberStringConverter converter = new NumberStringConverter(instance);
                holder.warn("V0项目成本毛利率异常：" + converter.toString(autoCost.getGrossProfitMargin()) + "<=0%");
                needImport = true;
            }
        }

        if (needImport && !autoCost.isImportLock()) {
            holder.debug("更新V0项目成本");
            getProjectCostService().updateAutoCost(project, holder);
        }

        // 检查最新的项目成本，默认 V1
        ProjectCost latestCost = getProjectCostService().findLatestByProject(project);
        if (latestCost == null) {
            ProjectCost cost = getProjectCostService().newInstanceByProject(project);
            cost.setVersion(1);
            Employee applicant = project.getApplicant();
            if (applicant == null) {
                applicant = contract.getEmployee();
            }
            cost.setApplicant(applicant);
            cost.setApplyTime(project.getCreated().atTime(LocalTime.now()));
            latestCost = getProjectCostService().save(cost);
        } else {
            //
            if (latestCost.getGrossProfitMargin() <= 0) {
                NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
                instance.setMaximumFractionDigits(2);
                NumberStringConverter converter = new NumberStringConverter(instance);
                holder.warn("V" + latestCost.getVersion() + "项目成本毛利率异常："
                        + converter.toString(latestCost.getGrossProfitMargin()) + "<=0%");
            } else if (latestCost.getGrossProfitMargin() >= 50) {
                NumberFormat instance = NumberFormat.getNumberInstance(getLocale());
                instance.setMaximumFractionDigits(2);
                NumberStringConverter converter = new NumberStringConverter(instance);
                holder.warn("V" + latestCost.getVersion() + "项目成本毛利率异常："
                        + converter.toString(latestCost.getGrossProfitMargin()) + ">=50%");
            }
        }

        if (project.isUseBid()) {
            List<ProjectBid> bids = getProjectBidService().findAllByProject(project);
            if (bids.isEmpty()) {
                holder.warn("投标未创建");
            }
        }
        if (project.isUseOffer()) {
            List<ProjectQuotation> quotations = getProjectQuotationService().findAllByProject(project);
            if (quotations.isEmpty()) {
                holder.warn("报价未创建");
            }
        }
    }

    private boolean verifyContractFileAsCustomer(Project project, Contract contract, MessageHolder holder) {
        boolean loseFile = false;
        List<ContractFile> files = getContractFileService().findAllByContract(contract);
        if (project != null) {
            // 投标
            if (project.isUseBid()) {
                // 投标审批表
                if (!hasFileType(files, ContractFileType.BidApprovalForm)) {
                    holder.error(getFileTypeLocalValue(ContractFileType.BidApprovalForm) + "未上传");
                    loseFile = true;
                }
                // 中标通知书
                if (!hasFileType(files, ContractFileType.BidAcceptanceLetter)) {
                    holder.error(getFileTypeLocalValue(ContractFileType.BidAcceptanceLetter) + "未上传");
                    loseFile = true;
                }
            }
            // 报价
            if (project.isUseOffer()) {
                if (!hasFileType(files, ContractFileType.QuotationApprovalForm)) {
                    holder.error(getFileTypeLocalValue(ContractFileType.QuotationApprovalForm) + "未上传");
                    loseFile = true;
                }
            }

            ProjectSaleType saleType = project.getSaleType();
            if (saleType != null) {
                List<ProjectSaleTypeRequireFileType> list = getSaleTypeRequireFileTypeService()
                        .findBySaleTypeId(saleType.getId());
                for (ProjectSaleTypeRequireFileType item : list) {
                    ContractFileType fileType = item.getFileType();
                    if (fileType != null) {
                        if (!hasFileType(files, fileType)) {
                            holder.error(getFileTypeLocalValue(fileType) + "未上传");
                            loseFile = true;
                        }
                    }
                }
                saleType = getSaleTypeService().findById(saleType.getId());
                if (saleType.isCriticalProjectDecision()) {
                    if (contract.getAmount() != null && contract.getAmount() >= saleType.getCriticalProjectLimit()) {
                        holder.debug("合同金额 " + contract.getAmount() + " 超过 " + saleType.getCriticalProjectLimit());
                        if (!hasFileType(files, ContractFileType.CriticalProjectDecisionRecord)) {
                            holder.error(getFileTypeLocalValue(ContractFileType.CriticalProjectDecisionRecord) + "未上传");
                            loseFile = true;
                        }
                    }
                }
            }
        }
        if (loseFile && files.isEmpty()) {
            holder.warn("!上传文件空!");
        }

        return !loseFile;
    }
}
