package com.trade.client.enterprise.customer.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.trade.client.enterprise.customer.constant.CustConstant;
import com.trade.client.enterprise.customer.domain.CustomerUser;
import com.trade.client.enterprise.customer.domain.model.LoginUserInfo;
import com.trade.client.enterprise.customer.service.CustomerMessageService;
import com.trade.client.enterprise.customer.service.CustomerUserService;
import com.trade.client.enterprise.customer.dto.EnterpriseStatusDto;
import com.trade.client.enterprise.customer.service.EnterpriseService;
import com.trade.client.security.utils.UserUtils;
import com.trade.common.constant.HttpStatus;
import com.trade.common.exception.ServiceException;
import com.trade.common.exception.ValidatorException;
import com.trade.common.utils.ConstantUtil;
import com.trade.common.utils.DateUtils;
import com.trade.common.utils.LoggerUtil;
import com.trade.common.utils.StringUtils;
import com.trade.common.utils.bean.Builder;
import com.trade.common.validate.ValidatorGroup;
import com.trade.common.validate.ValidatorUtil;
import com.trade.service.DictConstants;
import com.trade.service.business.payableaccounts.dto.ServiceFeeDto;
import com.trade.service.business.payableaccounts.service.PayableAccountsService;
import com.trade.service.contract.constant.ContractConstant;
import com.trade.service.contract.dto.*;
import com.trade.service.contract.service.ContractService;
import com.trade.service.contract.util.esign.ESignConstant;
import com.trade.service.filestorage.enums.FileTypeEnum;
import com.trade.service.TransStruct;
import com.trade.service.filestorage.entity.BusinessRelateFile;
import com.trade.service.enterprise.customer.domain.Enterprise;
import com.trade.service.enterprise.customer.domain.EnterpriseChangeRecord;
import com.trade.service.enterprise.customer.domain.EnterpriseRelatedPerson;
import com.trade.service.enterprise.customer.dto.EnterpriseDto;
import com.trade.service.enterprise.customer.dto.EnterpriseRelatedPersonDto;
import com.trade.service.filestorage.service.BusinessRelateFileBaseService;
import com.trade.service.enterprise.customer.service.EnterpriseBaseService;
import com.trade.service.enterprise.customer.service.EnterpriseChangeRecordBaseService;
import com.trade.service.enterprise.customer.service.EnterpriseRelatedPersonBaseService;
import com.trade.service.enterprise.customer.service.impl.EnterpriseDataConverter;
import com.trade.service.thirdparty.sop.dto.*;
import com.trade.service.thirdparty.sop.service.SOPService;
import com.trade.service.thirdparty.xiaotu.configuration.XiaotuConfiguration;
import com.trade.service.thirdparty.xiaotu.dto.*;
import com.trade.service.thirdparty.xiaotu.service.XiaotuRequestService;
import com.trade.service.trade.salescontract.domain.ContractFile;
import com.trade.service.trade.salescontract.service.ContractFileService;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 企业信息服务实现类
 *
 * @author hlb
 * @since 2024-05-29 15:02:09
 */
@Service("enterpriseService")
public class EnterpriseServiceImpl implements EnterpriseService {

    private static final Logger log = LoggerUtil.logger(LoggerUtil.LogFileNameEnum.SERVICES_LOG);
    @Value("${trade.website}")
    private String website;
    @Value("${taxRebate.serviceFee.amount:0.00}")
    private BigDecimal taxRebateServiceFeeAmount;
    @Value("${taxRebate.serviceFee.payeeName:上海银颗科技服务有限公司}")
    private String taxRebateServiceFeePayeeName;
    @Resource
    private CustomerMessageService customerMessageService;
    @Resource
    private EnterpriseBaseService enterpriseBaseService;
    @Resource
    private EnterpriseChangeRecordBaseService enterpriseChangeRecordBaseService;
    @Resource
    private EnterpriseDataConverter enterpriseDataConverter;
    @Resource
    private BusinessRelateFileBaseService businessRelateFileBaseService;
    @Resource
    private EnterpriseRelatedPersonBaseService enterpriseRelatedPersonBaseService;
    @Resource
    private XiaotuRequestService xiaotuRequestService;
    @Resource
    private CustomerUserService customerUserService;
    @Resource
    private TransStruct transStruct;
    @Resource
    private XiaotuConfiguration xiaotuConfiguration;
    @Resource
    private ContractService contractService;
    @Resource
    private ContractFileService contractFileService;
    @Resource
    private PayableAccountsService payableAccountsService;
    @Resource
    private SOPService sopService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public EnterpriseStatusDto queryCertificationStatus() {
        EnterpriseStatusDto enterpriseStatusDto = new EnterpriseStatusDto();
        enterpriseStatusDto.setCertificationStatus(DictConstants.CERTIFICATION_STATUS_UNSUBMITTED);
        enterpriseStatusDto.setShowAllFunctions(Boolean.FALSE);
        Long customerUserId = UserUtils.getCustomerUserId();
        EnterpriseChangeRecord record = enterpriseChangeRecordBaseService.getLatestRecord(customerUserId, null);
        if (record != null) {
            enterpriseStatusDto.setCertificationStatus(record.getCertificationStatus());
        }
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(customerUserId);
        enterpriseStatusDto.setShowAllFunctions(enterprise != null
                && DictConstants.CERTIFICATION_STATUS_PASSED.equals(enterprise.getCertificationStatus()));
        boolean validityPeriod = judgeTaxRebateServiceValidityPeriod(enterprise);
        enterpriseStatusDto.setShowTaxRebateApplyMenu(enterprise != null && getShowTaxRebateApplyMenu(enterprise));
        enterpriseStatusDto.setShowApplyTaxRebateBtn(
                enterprise != null && !validityPeriod && getShowApplyTaxRebateBtn(enterprise));
        enterpriseStatusDto
                .setShowTaxRebateBtn(enterprise != null && validityPeriod && getShowTaxRebateBtn(enterprise));
        return enterpriseStatusDto;
    }

    private boolean getShowTaxRebateApplyMenu(Enterprise enterprise) {
        if (!DictConstants.CERTIFICATION_STATUS_PASSED.equals(enterprise.getCertificationStatus())) {
            return false;
        }
        // 自营出口的企业展示“出口退税申请”菜单（或者曾经是自营出口的企业，且签署过协议的企业）
        return DictConstants.CONTRACT_STATUS_DONE.equals(enterprise.getTaxRebateAgreementSignStatus())
                || DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType());
    }

    private boolean getShowApplyTaxRebateBtn(Enterprise enterprise) {
        // 未申请出口退税，或者退税服务协议签署失败的自营出口企业展示“申请出口退税”按钮
        return (StrUtil.isBlank(enterprise.getTaxRebateAgreementSignStatus())
                || DictConstants.CONTRACT_STATUS_UNSIGNED.equals(enterprise.getTaxRebateAgreementSignStatus())
                || DictConstants.CONTRACT_FAILED_STATUS_LIST.contains(enterprise.getTaxRebateAgreementSignStatus()))
                && DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType());
    }

    private boolean getShowTaxRebateBtn(Enterprise enterprise) {
        // 签署了退税服务协议的自营出口企业可进行“出口退税”操作
        return DictConstants.CONTRACT_STATUS_DONE.equals(enterprise.getTaxRebateAgreementSignStatus())
                && DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType());
    }

    private boolean judgeTaxRebateServiceValidityPeriod(Enterprise enterprise) {
        if (enterprise == null) {
            return false;
        }
        // 退税服务有效期为1年
        if (enterprise.getTaxRebateEffectiveStart() == null || enterprise.getTaxRebateEffectiveEnd() == null) {
            return false;
        }
        Date now = new Date();
        if (now.after(enterprise.getTaxRebateEffectiveStart()) && now.before(enterprise.getTaxRebateEffectiveEnd())) {
            return true;
        } else {
            // 更新清空有效期和签署状态
            enterprise.setTaxRebateEffectiveStart(null);
            enterprise.setTaxRebateEffectiveEnd(null);
            enterprise.setTaxRebateAgreementSignStatus(null);
            enterprise.setChangeRecordId(null);
            EnterpriseDto enterpriseDto = enterpriseDataConverter.EnterpriseDomainToDto(enterprise);
            // 更新变更记录
            long recordId = saveEnterpriseChangeRecord(enterpriseDto);
            enterprise.setChangeRecordId(recordId);
            enterpriseBaseService.updateById(enterprise);
            return false;
        }
    }

    @Override
    public EnterpriseDto queryForUpdate() {
        Long customerUserId = UserUtils.getCustomerUserId();
        EnterpriseChangeRecord record = enterpriseChangeRecordBaseService.getLatestRecord(customerUserId, null);
        if (record == null) {
            return null;
        }
        return enterpriseDataConverter.recordToEnterpriseDto(record);
    }

    @Override
    public EnterpriseDto queryMyEnterprise() {
        Long customerUserId = UserUtils.getCustomerUserId();
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(customerUserId);
        if (enterprise != null) {
            return enterpriseDataConverter.EnterpriseDomainToDto(enterprise);
        } else {
            return this.queryForUpdate();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveEnterprise(String operate, EnterpriseDto enterpriseDto) {
        boolean firstSubmit = firstSubmitJudge(operate, enterpriseDto);
        LoginUserInfo loginUserInfo = UserUtils.getLoginUser();
        enterpriseDto.setCustomerId(loginUserInfo.getCustomerUserId());
        enterpriseDto.setCustomerIdentifierNo(loginUserInfo.getCustomerUser().getIdentifierNo());
        if (StrUtil.isEmpty(enterpriseDto.getCountryCode())) {
            enterpriseDto.setCountryCode(DictConstants.COUNTRY_CODE_CN);
        }
        checkParams(operate, enterpriseDto);
        boolean signAuthFile = resetChangeRecordIdAndJudgeSignAuthFile(loginUserInfo.getCustomerUserId(), operate,
                enterpriseDto);
        // 比较有无字段发生变化
        if (!isChanged(enterpriseDto)) {
            log.info("企业信息无变化，无需保存！");
            return null;
        }
        enterpriseDto.setCertificationStatus(DictConstants.CERTIFICATION_STATUS_PROCESSING);
        if (operate.equalsIgnoreCase(ConstantUtil.OPERATE_TYPE_SUBMIT)) {
            enterpriseDto.setCertificationStatus(DictConstants.CERTIFICATION_STATUS_PASSED);
            String product = matchProduct(enterpriseDto);
            enterpriseDto.setBusinessProduct(product);
            Enterprise enterprise = transStruct.transDto2Enterprise(enterpriseDto);
            enterpriseBaseService.saveOrUpdate(enterprise);
            enterpriseDto.setId(enterprise.getId());
        }
        // 保存企业变更流水
        long recordId = saveEnterpriseChangeRecord(enterpriseDto);
        // 保存企业证照信息
        saveEnterprisePictures(enterpriseDto, recordId);
        if (operate.equalsIgnoreCase(ConstantUtil.OPERATE_TYPE_SUBMIT)) {
            // 更新企业的流水id
            enterpriseBaseService.lambdaUpdate().eq(Enterprise::getId, enterpriseDto.getId())
                    .set(Enterprise::getChangeRecordId, recordId).update();
        }
        // 保存人员（法人、实控人）信息
        saveEnterprisePersons(enterpriseDto, recordId);
        // 第一提交则注册小图用户与企业信息
        if (firstSubmit && !xiaotuConfiguration.getTestMode()) {
            registerXiaotuUserAndEnterprise(enterpriseDto, loginUserInfo.getCustomerUser());
        }
        if (signAuthFile) {
            // 签署授权书
            signAuthFile(enterpriseDto);
        }
        return recordId;
    }

    /**
     * 签署授权文件
     * 
     * @param enterpriseDto
     */
    private void signAuthFile(EnterpriseDto enterpriseDto) {
        EnterpriseRelatedPersonDto authorizedPerson = enterpriseDto.getContactPerson();
        EnterpriseRelatedPersonDto legalPerson = enterpriseDto.getLegalPerson();
        ContractGenInputItem item = getContractGenInputItem(enterpriseDto, legalPerson, authorizedPerson);
        ContractGenOutputItem contractGenOutput = contractService.generateSingleContract(item,
                enterpriseDto.getCustomerId());
        if (contractGenOutput == null) {
            throw new ValidatorException(HttpStatus.ERROR, "授权书生成失败！");
        }
        // 保存未签署的授权书文件
        Long unsignedAuthFile = contractGenOutput.getFileId();
        BusinessRelateFile authFile = Builder.of(BusinessRelateFile.class)
                .with(BusinessRelateFile::setBelongId, authorizedPerson.getId())
                .with(BusinessRelateFile::setBelongType, ConstantUtil.ENTERPRISE_PERSON)
                .with(BusinessRelateFile::setFileType, FileTypeEnum.AUTHORIZATION_FILE.getCode())
                .with(BusinessRelateFile::setFileId, unsignedAuthFile).build();
        businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(authFile));
        // 构建签署参数，并签署授权书
        ContractSignInput signInput = getContractSignInput(enterpriseDto.getName(), enterpriseDto.getCertNo(),
                "跨境通-授权委托书", ContractConstant.SIGN_BIZ_TYPE_AUTHORIZATION_LETTER, legalPerson, unsignedAuthFile);
        ContractSignOutput contractSignOutput = contractService.signContract(signInput);
        if (contractSignOutput == null || CollUtil.isEmpty(contractSignOutput.getItems())) {
            throw new ValidatorException(HttpStatus.ERROR, "授权书签署处理失败！");
        }
        ContractFile contractFile = new ContractFile();
        // 授权书没有合同号，这里contractNo设置为授权人id（为了方便关联）
        contractFile.setOperatorName("C端用户:" + enterpriseDto.getCustomerId());
        contractFile.setCustomerUserId(enterpriseDto.getCustomerId());
        contractFile.setContractNo(authorizedPerson.getId().toString());
        contractFile.setSignFileType(FileTypeEnum.AUTHORIZATION_FILE.getCode());
        contractFile.setSignFileId(contractSignOutput.getItems().get(0).getThirdFileId());
        contractFile.setUnsignFileStorageId(unsignedAuthFile);
        contractFile.setSignFlowId(contractSignOutput.getFlowId());
        contractFileService.save(contractFile);
        // 更新授权书签署状态:签署中
        enterpriseRelatedPersonBaseService.lambdaUpdate().eq(EnterpriseRelatedPerson::getId, authorizedPerson.getId())
                .set(EnterpriseRelatedPerson::getAuthorizationFileSigned, DictConstants.CONTRACT_STATUS_SIGNING)
                .update();
    }

    @NotNull
    private ContractGenInputItem getContractGenInputItem(EnterpriseDto enterpriseDto,
            EnterpriseRelatedPersonDto legalPerson, EnterpriseRelatedPersonDto authorizedPerson) {
        ContractGenInputItem inputItem = new ContractGenInputItem();
        inputItem.setTemplateCode(FileTypeEnum.AUTHORIZATION_FILE.getCode());
        inputItem.setContractName("授权委托书-跨境通");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("enterpriseName", enterpriseDto.getName());
        dataMap.put("legalPerson", legalPerson.getName());
        dataMap.put("authorizedPerson", authorizedPerson.getName());
        dataMap.put("authorizedCertNo", authorizedPerson.getPersonalCertNo());
        dataMap.put("authorizedMobile", authorizedPerson.getMobile());
        dataMap.put("website", website);
        inputItem.setParams(dataMap);
        return inputItem;
    }

    @NotNull
    private ContractSignInput getContractSignInput(String enterpriseName, String EnterpriseCertNo, String bizScene,
            String bizType, EnterpriseRelatedPersonDto legalPerson, Long fileId) {
        ContractSignInput signInput = new ContractSignInput();
        signInput.setBizScene(bizScene);
        signInput.setBizType(bizType);
        ContractSignInfo contractSignInfo = new ContractSignInfo();
        contractSignInfo.setFileId(fileId);
        contractSignInfo.setFileType(FileTypeEnum.AUTHORIZATION_FILE.getCode());
        ContractSigner signer = new ContractSigner();
        signer.setSigner(legalPerson.getName());
        signer.setSignerIdNo(legalPerson.getPersonalCertNo());
        signer.setSignerIdType(ESignConstant.CRED_PSN_CH_IDCARD);
        signer.setMobile(legalPerson.getMobile());
        contractSignInfo.setSingleSigner(signer);
        List<ContractSeal> sealInfoList = new ArrayList<>();
        ContractSeal companySeal = new ContractSeal();
        // companySeal.setSigner(signer); 不设置时取singleSigner
        companySeal.setKeyword(ESignConstant.KEYWORD_COMPANY);
        companySeal.setSealIdType(ESignConstant.CRED_ORG_USCC);
        companySeal.setSealName(enterpriseName);
        companySeal.setSealIdNo(EnterpriseCertNo);
        companySeal.setWithTime(true);
        sealInfoList.add(companySeal);
        ContractSeal legalSeal = new ContractSeal();
        // legalSeal.setSigner(signer); 不设置时以签署人作为签章人
        legalSeal.setKeyword(ESignConstant.KEYWORD_PERSONAL);
        legalSeal.setWithTime(true);
        sealInfoList.add(legalSeal);
        contractSignInfo.setSealInfoList(sealInfoList);
        signInput.setSigneInfoList(Collections.singletonList(contractSignInfo));
        return signInput;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean applyTaxRebatePermission() {
        LoginUserInfo loginUser = UserUtils.getLoginUser();
        Long customerUserId = loginUser.getCustomerUserId();
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByCustomerId(customerUserId);
        if (enterprise == null
                || !DictConstants.CERTIFICATION_STATUS_PASSED.equals(enterprise.getCertificationStatus())) {
            throw new ServiceException("企业未认证，请先认证！", HttpStatus.BAD_REQUEST);
        }
        if (!DictConstants.EXPORT_TYPE_SELF.equals(enterprise.getExportType())) {
            throw new ServiceException("非自营出口企业，无需申请出口退税！", HttpStatus.BAD_REQUEST);
        }
        if (DictConstants.CONTRACT_STATUS_DONE.equals(enterprise.getTaxRebateAgreementSignStatus())
                || DictConstants.CONTRACT_STATUS_SIGNING.equals(enterprise.getTaxRebateAgreementSignStatus())) {
            return false;
        }
        if (StrUtil.isBlank(enterprise.getXtEid()) || StrUtil.isBlank(loginUser.getCustomerUser().getXtUid())) {
            throw new ServiceException("请先绑定退税企业、用户！", HttpStatus.BAD_REQUEST);
        }
        signTaxRebateAgreement(enterprise);
        return true;
    }

    private void signTaxRebateAgreement(Enterprise enterprise) {
        EnterpriseRelatedPerson legalPerson = enterpriseRelatedPersonBaseService
                .getLegalByChangeRecordId(enterprise.getChangeRecordId());
        if (legalPerson == null) {
            throw new ServiceException("企业法人信息不存在", HttpStatus.BAD_REQUEST);
        }
        EnterpriseRelatedPersonDto legalPersonDto = transStruct.transDto2EnterpriseRelatedPerson(legalPerson);
        ContractGenInputItem inputItem = new ContractGenInputItem();
        inputItem.setTemplateCode(FileTypeEnum.TAX_REBATE_AGREEMENT.getCode());
        inputItem.setContractName("退税服务协议");
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("enterpriseName", enterprise.getName());
        dataMap.put("legalPerson", legalPerson.getName());
        inputItem.setParams(dataMap);
        ContractGenOutputItem contractGenOutput = contractService.generateSingleContract(inputItem,
                enterprise.getCustomerId());
        if (contractGenOutput == null) {
            throw new ValidatorException(HttpStatus.ERROR, "退税服务协议生成失败！");
        }
        // 保存未签署的授权书文件
        Long unsignedAuthFile = contractGenOutput.getFileId();
        BusinessRelateFile authFile = Builder.of(BusinessRelateFile.class)
                .with(BusinessRelateFile::setBelongId, enterprise.getChangeRecordId())
                .with(BusinessRelateFile::setBelongType, ConstantUtil.ENTERPRISE_ACCESS)
                .with(BusinessRelateFile::setFileType, FileTypeEnum.TAX_REBATE_AGREEMENT.getCode())
                .with(BusinessRelateFile::setFileId, unsignedAuthFile).build();
        businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(authFile));
        // 构建签署参数，并签署授权书
        ContractSignInput signInput = getContractSignInput(enterprise.getName(), enterprise.getCertNo(), "退税服务协议",
                ContractConstant.SIGN_BIZ_TYPE_TAX_REBATE_AGREEMENT, legalPersonDto, unsignedAuthFile);
        ContractSignOutput contractSignOutput = contractService.signContract(signInput);
        if (contractSignOutput == null || CollUtil.isEmpty(contractSignOutput.getItems())) {
            throw new ValidatorException(HttpStatus.ERROR, "退税服务协议签署处理失败！");
        }
        ContractFile contractFile = new ContractFile();
        // 授权书没有合同号，这里contractNo设置为授权人id（为了方便关联）
        contractFile.setOperatorName("C端用户:" + enterprise.getCustomerId());
        contractFile.setCustomerUserId(enterprise.getCustomerId());
        contractFile.setContractNo(enterprise.getChangeRecordId().toString());
        contractFile.setSignFileType(FileTypeEnum.TAX_REBATE_AGREEMENT.getCode());
        contractFile.setSignFileId(contractSignOutput.getItems().get(0).getThirdFileId());
        contractFile.setUnsignFileStorageId(unsignedAuthFile);
        contractFile.setSignFlowId(contractSignOutput.getFlowId());
        contractFileService.save(contractFile);
        // 更新退税服务协议签署状态:签署中
        enterpriseBaseService.lambdaUpdate().eq(Enterprise::getId, enterprise.getId())
                .set(Enterprise::getTaxRebateAgreementSignStatus, DictConstants.CONTRACT_STATUS_SIGNING).update();
        enterpriseChangeRecordBaseService.lambdaUpdate()
                .eq(EnterpriseChangeRecord::getId, enterprise.getChangeRecordId())
                .set(EnterpriseChangeRecord::getTaxRebateAgreementSignStatus, DictConstants.CONTRACT_STATUS_SIGNING)
                .update();
    }

    /**
     * 电子签署回调处理
     * 
     * @param bizData
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void process(SignCallback2Biz bizData) {
        String status;
        if (bizData.getSignStatus().equals(ContractConstant.CONTRACT_SIGN_STATUS_UNSIGNED)) {
            return;
        } else if (ContractConstant.CONTRACT_SIGN_STATUS_EXPIRED.equals(bizData.getSignStatus())) {
            status = DictConstants.CONTRACT_STATUS_SIGNED_TIMEOUT;
        } else if (ContractConstant.CONTRACT_SIGN_STATUS_REJECTED.equals(bizData.getSignStatus())) {
            status = DictConstants.CONTRACT_STATUS_SIGNED_REJECTED;
        } else if (bizData.getSignStatus().equals(ContractConstant.CONTRACT_SIGN_STATUS_SIGNED)) {
            status = DictConstants.CONTRACT_STATUS_DONE;
        } else {
            throw new ServiceException("未知的签署状态：" + bizData.getSignStatus(), HttpStatus.BAD_REQUEST);
        }
        List<ContractFile> list = contractFileService.selectBySignFlowId(bizData.getSignFlowId());
        if (CollUtil.isEmpty(list)) {
            throw new ServiceException("未找到合同文件信息", HttpStatus.BAD_REQUEST);
        }
        ContractFile contractFile = list.get(0);
        if (bizData.getBizType().equals(ContractConstant.SIGN_BIZ_TYPE_TAX_REBATE_AGREEMENT)) {
            handleTaxRebateAgreementSign(bizData, status, contractFile);
        } else {
            handleAuthorizationLetterSign(bizData, status, contractFile);
        }
    }

    private void handleAuthorizationLetterSign(SignCallback2Biz bizData, String status, ContractFile contractFile) {
        Long authorizedPersonId = Long.parseLong(contractFile.getContractNo());
        if (DictConstants.CONTRACT_STATUS_DONE.equals(status)) {
            SignCallback2Biz.SignedFile2Biz signedFile2Biz = bizData.getSignedFiles().stream()
                    .filter(f -> FileTypeEnum.AUTHORIZATION_FILE.getCode().equals(f.getFileType())
                            && Objects.equals(f.getRawFileId(), contractFile.getUnsignFileStorageId()))
                    .findFirst().orElseThrow(() -> new ServiceException("未找到授权书文件信息", HttpStatus.BAD_REQUEST));
            BusinessRelateFile businessRelateFile = new BusinessRelateFile();
            businessRelateFile.setBelongId(authorizedPersonId);
            businessRelateFile.setBelongType(ConstantUtil.ENTERPRISE_PERSON);
            businessRelateFile.setFileId(signedFile2Biz.getFileId());
            businessRelateFile.setFileType(contractFile.getSignFileType());
            contractFile.setSignedFileStorageId(signedFile2Biz.getFileId());
            contractFileService.updateById(contractFile);
            businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
        }
        // 更新授权书签署状态:status
        enterpriseRelatedPersonBaseService.lambdaUpdate().eq(EnterpriseRelatedPerson::getId, authorizedPersonId)
                .set(EnterpriseRelatedPerson::getAuthorizationFileSigned, status)
                .set(status.equals(DictConstants.CONTRACT_STATUS_DONE), EnterpriseRelatedPerson::getSignDate,
                        DateUtils.parseLocalDateTime2Date(bizData.getSignTime()))
                .update();
    }

    private void handleTaxRebateAgreementSign(SignCallback2Biz bizData, String status, ContractFile contractFile) {
        Long changeRecordId = Long.parseLong(contractFile.getContractNo());
        Enterprise enterprise = enterpriseBaseService.getEnterpriseByChangeRecordId(changeRecordId);
        if (enterprise == null) {
            throw new ServiceException("未找到企业信息", HttpStatus.BAD_REQUEST);
        }
        CustomerUser customerUser = customerUserService.getById(enterprise.getCustomerId());
        if (customerUser == null) {
            throw new ServiceException("未找到客户信息", HttpStatus.BAD_REQUEST);
        }
        if (DictConstants.CONTRACT_STATUS_DONE.equals(status)) {
            SignCallback2Biz.SignedFile2Biz signedFile2Biz = bizData.getSignedFiles().stream()
                    .filter(f -> FileTypeEnum.TAX_REBATE_AGREEMENT.getCode().equals(f.getFileType())
                            && Objects.equals(f.getRawFileId(), contractFile.getUnsignFileStorageId()))
                    .findFirst().orElseThrow(() -> new ServiceException("未找到退税服务协议文件信息", HttpStatus.BAD_REQUEST));
            BusinessRelateFile businessRelateFile = new BusinessRelateFile();
            businessRelateFile.setBelongId(changeRecordId);
            businessRelateFile.setBelongType(ConstantUtil.ENTERPRISE_ACCESS);
            businessRelateFile.setFileId(signedFile2Biz.getFileId());
            businessRelateFile.setFileType(contractFile.getSignFileType());
            contractFile.setSignedFileStorageId(signedFile2Biz.getFileId());
            contractFileService.updateById(contractFile);
            businessRelateFileBaseService.addBusinessRelateFiles(Collections.singletonList(businessRelateFile));
            // 生成“待支付退税服务费”记录
            ServiceFeeDto serviceFeeDto = new ServiceFeeDto();
            serviceFeeDto.setCustomerUserId(customerUser.getId());
            serviceFeeDto.setPaymentAmount(taxRebateServiceFeeAmount);
            serviceFeeDto.setPaymentCurrency("CNY");
            serviceFeeDto.setPaymentDeadline(bizData.getSignTime().plusHours(72));
            serviceFeeDto.setPayeeName(taxRebateServiceFeePayeeName);
            payableAccountsService.saveTaxRefundServiceFee(serviceFeeDto);
        }
        // 更新授权书签署状态:status
        enterpriseBaseService.lambdaUpdate().eq(Enterprise::getId, enterprise.getId())
                .set(Enterprise::getTaxRebateAgreementSignStatus, status)
                .set(status.equals(DictConstants.CONTRACT_STATUS_DONE), Enterprise::getTaxRebateAgreementSignDate,
                        DateUtils.parseLocalDateTime2Date(bizData.getSignTime()))
                .update();
        enterpriseChangeRecordBaseService.lambdaUpdate().eq(EnterpriseChangeRecord::getId, changeRecordId)
                .set(EnterpriseChangeRecord::getTaxRebateAgreementSignStatus, status)
                .set(status.equals(DictConstants.CONTRACT_STATUS_DONE),
                        EnterpriseChangeRecord::getTaxRebateAgreementSignDate,
                        DateUtils.parseLocalDateTime2Date(bizData.getSignTime()))
                .update();
    }

    /**
     * 当前认证中&&暂存 或者 当前已认证&&提交，不插入变更记录、直接更新上次记录 （减少变更表记录）
     * 
     * @param customerUserId
     * @param operate
     * @param enterpriseDto
     */
    private boolean resetChangeRecordIdAndJudgeSignAuthFile(Long customerUserId, String operate,
            EnterpriseDto enterpriseDto) {
        EnterpriseChangeRecord record = enterpriseChangeRecordBaseService.getLatestRecord(customerUserId, null);
        if (record != null && ((operate.equalsIgnoreCase(ConstantUtil.OPERATE_TYPE_SAVE)
                && record.getCertificationStatus().equals(DictConstants.CERTIFICATION_STATUS_PROCESSING))
                || (operate.equalsIgnoreCase(ConstantUtil.OPERATE_TYPE_SUBMIT)
                        && record.getCertificationStatus().equals(DictConstants.CERTIFICATION_STATUS_PASSED)))) {
            enterpriseDto.setChangeRecordId(record.getId());
        } else {
            enterpriseDto.setChangeRecordId(null);
            Optional.ofNullable(enterpriseDto.getContactPerson()).ifPresent(cp -> cp.setId(null));
            Optional.ofNullable(enterpriseDto.getLegalPerson()).ifPresent(cp -> cp.setId(null));
            Optional.ofNullable(enterpriseDto.getControlPerson()).ifPresent(cp -> cp.setId(null));
        }
        // 没有授权人信息，则不签署授权书
        EnterpriseRelatedPersonDto authorizedPerson = enterpriseDto.getContactPerson();
        if (authorizedPerson == null) {
            return false;
        }
        // 暂存时，不签署授权书
        if (operate.equalsIgnoreCase(ConstantUtil.OPERATE_TYPE_SAVE)) {
            return false;
        } else {
            record = enterpriseChangeRecordBaseService.getLatestRecord(customerUserId,
                    DictConstants.CERTIFICATION_STATUS_PASSED);
            // 首次提交，签署必须授权书
            if (record == null) {
                return true;
            }
            // 较上次提交，授权代理人是否变更或者上次授权失败，如有变更则签署
            EnterpriseRelatedPerson rawAuthorizedPerson = enterpriseRelatedPersonBaseService
                    .getContactByChangeRecordId(record.getId());
            return rawAuthorizedPerson == null
                    || DictConstants.CONTRACT_FAILED_STATUS_LIST
                            .contains(rawAuthorizedPerson.getAuthorizationFileSigned())
                    || StrUtil.equals(rawAuthorizedPerson.getName(), authorizedPerson.getName())
                    || StrUtil.equals(rawAuthorizedPerson.getPersonalCertNo(), authorizedPerson.getPersonalCertNo())
                    || StrUtil.equals(rawAuthorizedPerson.getEmail(), authorizedPerson.getEmail());
        }
    }

    /**
     * 判断是否是第一次提交
     * 
     * @param operate
     * @param enterpriseDto
     * @return
     */
    private boolean firstSubmitJudge(String operate, EnterpriseDto enterpriseDto) {
        boolean firstSubmit = operate.equalsIgnoreCase(ConstantUtil.OPERATE_TYPE_SUBMIT);
        if (firstSubmit) {
            Enterprise tempEnterprise = null;
            if (enterpriseDto.getId() == null) {
                tempEnterprise = enterpriseBaseService.getEnterpriseByCertNo(enterpriseDto.getCertNo());
            } else {
                tempEnterprise = enterpriseBaseService.getById(enterpriseDto.getId());
            }
            if (tempEnterprise != null) {
                enterpriseDto.setId(tempEnterprise.getId());
            }
            firstSubmit = tempEnterprise == null
                    || !DictConstants.CERTIFICATION_STATUS_PASSED.equals(tempEnterprise.getCertificationStatus());
        }
        return firstSubmit;
    }

    /**
     * 匹配企业业务类型
     * 
     * @return 业务类型
     */
    private String matchProduct(EnterpriseDto enterpriseDto) {
        if (DictConstants.EXPORT_TYPE_SELF.equals(enterpriseDto.getExportType())) {
            return DictConstants.PRODUCT_F_TRADE;
        } else if (DictConstants.EXPORT_TYPE_PROXY.equals(enterpriseDto.getExportType())
                && DictConstants.DISTRICT_CN_MAINLAND.equals(enterpriseDto.getProxyDistrictCode())) {
                    return DictConstants.PRODUCT_E_TRADE;
                } else {
                    return DictConstants.PRODUCT_CROSS_BORDER_TRADE;
                }
    }

    /**
     * 企业保存、提交检查参数
     *
     * @param operate 操作：保存（save）；或提交（submit）
     * @param enterpriseDto 企业信息
     */
    private void checkParams(String operate, EnterpriseDto enterpriseDto) {
        Long customerUserId = UserUtils.getCustomerUserId();
        enterpriseDto.setCustomerId(customerUserId);
        checkUnique(enterpriseDto);
        if (StrUtil.isBlank(enterpriseDto.getCountryCode())) {
            enterpriseDto.setCountryCode(DictConstants.COUNTRY_CODE_CN);
        }
        if (enterpriseDto.getContactPerson() != null
                && StrUtil.isNotEmpty(enterpriseDto.getContactPerson().getEmail())) {
            if (StrUtil.isEmpty(enterpriseDto.getEmailAuthCode())) {
                throw new ValidatorException(HttpStatus.ERROR, "请先获取邮箱验证码！");
            }
            // 邮箱验证码校验
            customerMessageService.checkEmailAuthCode(enterpriseDto.getContactPerson().getEmail(),
                    enterpriseDto.getEmailAuthCode(), CustConstant.USER_CERTIFICATION_TEMPLATE);
        }
        if (operate.equals(ConstantUtil.OPERATE_TYPE_SAVE)) {
            ValidatorUtil.validator(ValidatorGroup.ValidatorType.ADD, enterpriseDto);
            return;
        }
        ValidatorUtil.validator(ValidatorGroup.ValidatorType.SUBMIT, enterpriseDto);
        if (DictConstants.SYS_NO.equals(enterpriseDto.getSameRegisterAndBusinessAddress())
                && StrUtil.isEmpty(enterpriseDto.getBusinessAddress())) {
            throw new ValidatorException(HttpStatus.ERROR, "实际经营地址不能为空！");
        }
        ValidatorUtil.validator(ValidatorGroup.ValidatorType.SUBMIT, enterpriseDto.getContactPerson());
        ValidatorUtil.validator(ValidatorGroup.ValidatorType.SUBMIT, enterpriseDto.getLegalPerson());
        if (Objects.equals(enterpriseDto.getLegalPerson().getIsControl(), DictConstants.SYS_NO)) {
            if (enterpriseDto.getControlPerson() == null) {
                throw new ValidatorException(HttpStatus.ERROR, "企业实控人信息不能为空！");
            } else {
                ValidatorUtil.validator(ValidatorGroup.ValidatorType.SUBMIT, enterpriseDto.getControlPerson());
            }
        } else {
            enterpriseDto.setControlPerson(null);
        }
        if (StrUtil.isEmpty(enterpriseDto.getContactPerson().getEmail())) {
            throw new ValidatorException(HttpStatus.ERROR, "联系人邮箱不能为空！");
        }
        if (Objects.equals(enterpriseDto.getExportType(), DictConstants.EXPORT_TYPE_PROXY)
                && StrUtil.isEmpty(enterpriseDto.getProxyDistrictCode())) {
            throw new ValidatorException(HttpStatus.ERROR, "代理公司所属地区不能为空！");
        }
        // 企业准入
        checkAccess(enterpriseDto);
    }

    private void checkAccess(EnterpriseDto enterpriseDto) {
        int age = DateUtils.getAgeByIdCardNo(enterpriseDto.getLegalPerson().getPersonalCertNo());
        if (age < 18 || age > 60) {
            log.warn("企业准入失败，法人年龄不符合要求！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        // 调用sop接口 获取企查查信息
        SOPRiskInvestigation riskInvestigation = sopService.getRiskInvestigation(enterpriseDto.getCustomerId(),
                enterpriseDto.getCertNo());
        if (null == riskInvestigation) {
            log.warn("企业准入失败，企查查接口返回空！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        // 企业成立年限是否大于一年
        if (LocalDate.now().minusDays(365)
                .isBefore(LocalDateTimeUtil.parseDate(riskInvestigation.getStartDate(), DateUtils.YYYY_MM_DD))) {
            log.warn("企业准入失败，企业成立年限不符合要求！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        if (riskInvestigation.getRegistCapi() != null && StringUtils.parseMoney(riskInvestigation.getRegistCapi())
                .compareTo(Optional.ofNullable(riskInvestigation.getZhixingAmount()).orElse(BigDecimal.ZERO)) < 0) {
            log.warn("企业准入失败，企业被执行金额大于注册资本！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        // 企业高管是否存在失信被执行人或被限制高消费
        accessCheck4Management(enterpriseDto, riskInvestigation);
        // 企业经营异常检查
        accessCheck4BizException(enterpriseDto, riskInvestigation);
    }

    /**
     * 企业经营异常检查
     *
     * @param riskInvestigation 企查查信息
     */
    private void accessCheck4BizException(EnterpriseDto enterpriseDto, SOPRiskInvestigation riskInvestigation) {
        if (Boolean.TRUE.equals(riskInvestigation.getExistFinancialOrPrivateLending())) {
            log.warn("企业准入失败，企业存在民间借贷记录或金融诉讼！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        } else {// 由于SOP接口的编排逻辑，法院裁判文书需要单独调用，首次调用的时候一般都是没有的，需要单独调用一次,加上id条件可以避免短期内重复调用
            boolean existFinancialOrPrivateLending = sopService.getExistFinancialOrPrivateLending(
                    enterpriseDto.getCustomerId(), enterpriseDto.getCertNo(), riskInvestigation.getId());
            if (Boolean.TRUE.equals(existFinancialOrPrivateLending)) {
                log.warn("企业准入失败，企业存在民间借贷记录或金融诉讼！");
                throw new ValidatorException(HttpStatus.ERROR, "认证失败");
            }
        }
        if (riskInvestigation.getTaxAbnormalCount() != null && riskInvestigation.getTaxAbnormalCount() > 0) {
            log.warn("企业准入失败，企业存在税务非正常户记录！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        if (riskInvestigation.getSeriousIllegalCount() != null && riskInvestigation.getSeriousIllegalCount() > 0) {
            log.warn("企业准入失败，企业存在严重违法记录！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        if (riskInvestigation.getTaxOweNoticeCount() != null && riskInvestigation.getTaxOweNoticeCount() > 0) {
            log.warn("企业准入失败，企业存在欠税公告记录！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        if (riskInvestigation.getTaxIllegalCount() != null && riskInvestigation.getTaxIllegalCount() > 0) {
            log.warn("企业准入失败，企业存在税务违法记录！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
        if (riskInvestigation.getEquityFreezeCount() != null && riskInvestigation.getEquityFreezeCount() > 0) {
            log.warn("企业准入失败，企业存在股权冻结记录！");
            throw new ValidatorException(HttpStatus.ERROR, "认证失败");
        }
    }

    private void accessCheck4Management(EnterpriseDto enterpriseDto, SOPRiskInvestigation riskInvestigation) {
        boolean existCreditExecution = riskInvestigation.getShixin() != null && riskInvestigation.getShixin() > 0;
        boolean existConsumptionLimit = riskInvestigation.getSumptuary() != null
                && riskInvestigation.getSumptuary() > 0;
        if (existCreditExecution) {
            List<CDongjiangaoSxCheck> legalCreditExecutions = sopService.getManagementCreditExecution(
                    enterpriseDto.getCustomerId(), enterpriseDto.getCertNo(), enterpriseDto.getLegalPerson().getName());
            if (CollectionUtil.isNotEmpty(legalCreditExecutions)) {
                log.warn("企业准入失败，企业法人为失信被执行人！");
                throw new ValidatorException(HttpStatus.ERROR, "认证失败");
            }
        }
        if (existConsumptionLimit) {
            List<CDongjiangaoSumptuaryCheck> legalConsumptionLimits = sopService.getManagementConsumptionLimit(
                    enterpriseDto.getCustomerId(), enterpriseDto.getCertNo(), enterpriseDto.getLegalPerson().getName());
            if (CollectionUtil.isNotEmpty(legalConsumptionLimits)) {
                log.warn("企业准入失败，企业法人被限制高消费！");
                throw new ValidatorException(HttpStatus.ERROR, "认证失败");
            }
        }
        if (Objects.equals(enterpriseDto.getLegalPerson().getIsControl(), DictConstants.SYS_NO)) {
            if (existCreditExecution) {
                List<CDongjiangaoSxCheck> controlCreditExecutions = sopService.getManagementCreditExecution(
                        enterpriseDto.getCustomerId(), enterpriseDto.getCertNo(),
                        enterpriseDto.getControlPerson().getName());
                if (CollectionUtil.isNotEmpty(controlCreditExecutions)) {
                    log.warn("企业准入失败，企业实控人为失信被执行人！");
                    throw new ValidatorException(HttpStatus.ERROR, "认证失败");
                }
            }
            if (existConsumptionLimit) {
                List<CDongjiangaoSumptuaryCheck> controlConsumptionLimits = sopService.getManagementConsumptionLimit(
                        enterpriseDto.getCustomerId(), enterpriseDto.getCertNo(),
                        enterpriseDto.getControlPerson().getName());
                if (CollectionUtil.isNotEmpty(controlConsumptionLimits)) {
                    log.warn("企业准入失败，企业实控人被限制高消费！");
                    throw new ValidatorException(HttpStatus.ERROR, "认证失败");
                }
            }
        }
    }

    private void checkUnique(EnterpriseDto enterpriseDto) {
        boolean anyMatch = enterpriseChangeRecordBaseService.lambdaQuery()
                .eq(EnterpriseChangeRecord::getCertNo, enterpriseDto.getCertNo()).list().stream()
                .anyMatch(item -> !Objects.equals(item.getCustomerId(), enterpriseDto.getCustomerId()));
        if (anyMatch) {
            throw new ValidatorException(HttpStatus.ERROR, "企业统一社会信用代码已存在！");
        }
        anyMatch = enterpriseChangeRecordBaseService.lambdaQuery()
                .eq(EnterpriseChangeRecord::getName, enterpriseDto.getName()).list().stream()
                .anyMatch(item -> !Objects.equals(item.getCustomerId(), enterpriseDto.getCustomerId()));
        if (anyMatch) {
            throw new ValidatorException(HttpStatus.ERROR, "企业名称已存在！");
        }
        if (StrUtil.isNotEmpty(enterpriseDto.getTaxNo())) {
            anyMatch = enterpriseChangeRecordBaseService.lambdaQuery()
                    .eq(EnterpriseChangeRecord::getTaxNo, enterpriseDto.getTaxNo()).list().stream()
                    .anyMatch(item -> !Objects.equals(item.getCustomerId(), enterpriseDto.getCustomerId()));
            if (anyMatch) {
                throw new ValidatorException(HttpStatus.ERROR, "纳税人识别号已存在！");
            }
        }
        if (StrUtil.isNotEmpty(enterpriseDto.getCustomsEnterpriseCode())) {
            anyMatch = enterpriseChangeRecordBaseService.lambdaQuery()
                    .eq(EnterpriseChangeRecord::getCustomsEnterpriseCode, enterpriseDto.getCustomsEnterpriseCode())
                    .list().stream()
                    .anyMatch(item -> !Objects.equals(item.getCustomerId(), enterpriseDto.getCustomerId()));
            if (anyMatch) {
                throw new ValidatorException(HttpStatus.ERROR, "海关企业代码已存在！");
            }
        }
    }

    /**
     * 检查本次修改是否有变化
     *
     * @param enterpriseDto
     * @return
     */
    private boolean isChanged(EnterpriseDto enterpriseDto) {
        Long customerUserId = UserUtils.getCustomerUserId();
        EnterpriseChangeRecord record = enterpriseChangeRecordBaseService.getLatestRecord(customerUserId, null);
        if (record == null) {
            return true;
        }
        if (!StrUtil.equals(record.getEnterpriseType(), enterpriseDto.getEnterpriseType())) {
            return true;
        }
        if (!StrUtil.equals(record.getName(), enterpriseDto.getName())) {
            return true;
        }
        if (!StrUtil.equals(record.getCertNo(), enterpriseDto.getCertNo())) {
            return true;
        }
        if (!StrUtil.equals(record.getRegistrationNumber(), enterpriseDto.getRegistrationNumber())) {
            return true;
        }
        if (!StrUtil.equals(record.getCustomsEnterpriseCode(), enterpriseDto.getCustomsEnterpriseCode())) {
            return true;
        }
        if (!StrUtil.equals(record.getTaxNo(), enterpriseDto.getTaxNo())) {
            return true;
        }
        if (!Objects.equals(DateUtils.dateTime(record.getEstablishDate()),
                DateUtils.dateTime(enterpriseDto.getEstablishDate()))) {
            return true;
        }
        if ((record.getRegisterCapital() == null && enterpriseDto.getRegisterCapital() != null)
                || (record.getRegisterCapital() != null && enterpriseDto.getRegisterCapital() == null)
                || (record.getRegisterCapital() != null && enterpriseDto.getRegisterCapital() != null
                        && record.getRegisterCapital().compareTo(enterpriseDto.getRegisterCapital()) != 0)) {
            return true;
        }
        if (!StrUtil.equals(record.getRegisterAddress(), enterpriseDto.getRegisterAddress())) {
            return true;
        }
        if (!StrUtil.equals(record.getBusinessAddress(), enterpriseDto.getBusinessAddress())) {
            return true;
        }
        if (!StrUtil.equals(record.getSameRegisterAndBusinessAddress(),
                enterpriseDto.getSameRegisterAndBusinessAddress())) {
            return true;
        }
        if (!StrUtil.equals(record.getExportType(), enterpriseDto.getExportType())) {
            return true;
        }
        if (!StrUtil.equals(record.getProxyDistrictCode(), enterpriseDto.getProxyDistrictCode())) {
            return true;
        }
        if (!StrUtil.equals(record.getTaxAuthorityArea(), enterpriseDto.getTaxAuthorityArea())) {
            return true;
        }
        // 证照信息是否变更
        List<BusinessRelateFile> bizObjFiles = businessRelateFileBaseService.getBizObjFiles(record.getId(),
                ConstantUtil.ENTERPRISE_ACCESS, null);
        for (BusinessRelateFile businessRelateFile : bizObjFiles) {
            if (StrUtil.equals(businessRelateFile.getFileType(), FileTypeEnum.IDENTITY_CARD_FRONT.getCode())
                    && enterpriseDto.getLegalPerson() != null && !Objects.equals(businessRelateFile.getFileId(),
                            enterpriseDto.getLegalPerson().getIdCardFront().getId())) {
                return true;
            } else if (StrUtil.equals(businessRelateFile.getFileType(), FileTypeEnum.IDENTITY_CARD_BACK.getCode())
                    && enterpriseDto.getLegalPerson() != null && !Objects.equals(businessRelateFile.getFileId(),
                            enterpriseDto.getLegalPerson().getIdCardBack().getId())) {
                                return true;
                            } else
                if (StrUtil.equals(businessRelateFile.getFileType(), FileTypeEnum.IDENTITY_CARD_FRONT.getCode())
                        && enterpriseDto.getControlPerson() != null && !Objects.equals(businessRelateFile.getFileId(),
                                enterpriseDto.getControlPerson().getIdCardFront().getId())) {
                                    return true;
                                } else
                    if (StrUtil.equals(businessRelateFile.getFileType(), FileTypeEnum.IDENTITY_CARD_BACK.getCode())
                            && enterpriseDto.getControlPerson() != null
                            && !Objects.equals(businessRelateFile.getFileId(),
                                    enterpriseDto.getControlPerson().getIdCardBack().getId())) {
                                        return true;
                                    } else
                        if (StrUtil.equals(businessRelateFile.getFileType(), FileTypeEnum.IDENTITY_CARD_FRONT.getCode())
                                && enterpriseDto.getContactPerson() != null
                                && !Objects.equals(businessRelateFile.getFileId(),
                                        enterpriseDto.getContactPerson().getIdCardFront().getId())) {
                                            return true;
                                        } else
                            if (StrUtil.equals(businessRelateFile.getFileType(),
                                    FileTypeEnum.IDENTITY_CARD_BACK.getCode())
                                    && enterpriseDto.getContactPerson() != null
                                    && !Objects.equals(businessRelateFile.getFileId(),
                                            enterpriseDto.getContactPerson().getIdCardBack().getId())) {
                                                return true;
                                            } else
                                if (StrUtil.equals(businessRelateFile.getFileType(),
                                        FileTypeEnum.BUSINESS_LICENSE.getCode())
                                        && !Objects.equals(businessRelateFile.getFileId(),
                                                enterpriseDto.getBusinessLicense().getId())) {
                                                    return true;
                                                }
        }
        // 人员信息是否变更
        if (isPersonBasicInfoChanged(enterpriseDto.getLegalPerson(), record)) {
            return true;
        }
        if (isPersonBasicInfoChanged(enterpriseDto.getControlPerson(), record)) {
            return true;
        }
        if (isPersonBasicInfoChanged(enterpriseDto.getContactPerson(), record)) {
            return true;
        }
        return false;
    }

    /**
     * 检查人员基本信息是否有变化
     *
     * @param personDto
     */
    private boolean isPersonBasicInfoChanged(EnterpriseRelatedPersonDto personDto, EnterpriseChangeRecord record) {
        if (personDto == null) {
            return false;
        }
        if (record == null) {
            return true;
        }
        List<EnterpriseRelatedPerson> persons = enterpriseRelatedPersonBaseService
                .getPersonsByChangeRecordId(record.getId());
        if (CollUtil.isEmpty(persons)) {
            return true;
        }
        EnterpriseRelatedPerson enterpriseRelatedPerson = persons.stream()
                .filter(p -> Objects.equals(p.getIsAuthorizedPerson(), personDto.getIsAuthorizedPerson())
                        && Objects.equals(p.getIsLegalPerson(), personDto.getIsLegalPerson())
                        && Objects.equals(p.getIsControl(), personDto.getIsControl()))
                .collect(Collectors.toList()).stream().findFirst().orElse(null);
        if (enterpriseRelatedPerson == null) {
            return true;
        }
        if (!StrUtil.equals(personDto.getName(), personDto.getName())) {
            return true;
        }
        if (!StrUtil.equals(personDto.getEmail(), personDto.getEmail())) {
            return true;
        }
        if (!StrUtil.equals(personDto.getMobile(), personDto.getMobile())) {
            return true;
        }
        if (!StrUtil.equals(personDto.getPersonalCertNo(), personDto.getPersonalCertNo())) {
            return true;
        }
        return false;
    }

    /**
     * 保存企业变更记录
     *
     * @param enterpriseDto
     * @return
     */
    private long saveEnterpriseChangeRecord(EnterpriseDto enterpriseDto) {
        EnterpriseChangeRecord record = transStruct.transEnterpriseDto2EnterpriseChangeRecord(enterpriseDto);
        if (record == null) {
            throw new ValidatorException(HttpStatus.ERROR, "企业变更记录保存失败！");
        }
        enterpriseChangeRecordBaseService.saveOrUpdate(record);
        return record.getId();
    }

    /**
     * 保存企业证件信息
     *
     * @param enterpriseDto
     */
    private void saveEnterprisePictures(EnterpriseDto enterpriseDto, Long changeRecordId) {
        List<BusinessRelateFile> enterprisePictures = new ArrayList<>();
        if (enterpriseDto.getBusinessLicense() != null) {
            BusinessRelateFile businessLicense = Builder.of(BusinessRelateFile.class)
                    .with(BusinessRelateFile::setBelongId, changeRecordId)
                    .with(BusinessRelateFile::setBelongType, ConstantUtil.ENTERPRISE_ACCESS)
                    .with(BusinessRelateFile::setFileType, FileTypeEnum.BUSINESS_LICENSE.getCode())
                    .with(BusinessRelateFile::setFileId, enterpriseDto.getBusinessLicense().getId()).build();
            enterprisePictures.add(businessLicense);
        }
        if (CollUtil.isNotEmpty(enterprisePictures)) {
            businessRelateFileBaseService.addBusinessRelateFiles(enterprisePictures);
        }
    }

    /**
     * 保存企业人员信息
     *
     * @param enterpriseDto
     */
    private void saveEnterprisePersons(EnterpriseDto enterpriseDto, Long changeRecordId) {
        saveEnterprisePersons(enterpriseDto.getLegalPerson(), changeRecordId);
        saveEnterprisePersons(enterpriseDto.getControlPerson(), changeRecordId);
        saveEnterprisePersons(enterpriseDto.getContactPerson(), changeRecordId);
    }

    private void saveEnterprisePersons(EnterpriseRelatedPersonDto personDto, Long changeRecordId) {
        if (personDto != null) {
            EnterpriseRelatedPerson person = transStruct.transEnterpriseRelatedPerson2Dto(personDto);
            person.setEnterpriseChangeRecordId(changeRecordId);
            if (StrUtil.isBlank(person.getCountryCode())) {
                person.setCountryCode(DictConstants.COUNTRY_CODE_CN);
            }
            if (StrUtil.isBlank(person.getPersonalCertType())) {
                person.setPersonalCertType(DictConstants.PERSONAL_CERT_TYPE_CN_IDCARD);
            }
            enterpriseRelatedPersonBaseService.saveOrUpdate(person);
            personDto.setId(person.getId());
            List<BusinessRelateFile> personFiles = new ArrayList<>();
            if (personDto.getIdCardFront() != null) {
                BusinessRelateFile idCardFront = Builder.of(BusinessRelateFile.class)
                        .with(BusinessRelateFile::setBelongId, person.getId())
                        .with(BusinessRelateFile::setBelongType, ConstantUtil.ENTERPRISE_PERSON)
                        .with(BusinessRelateFile::setFileType, FileTypeEnum.IDENTITY_CARD_FRONT.getCode())
                        .with(BusinessRelateFile::setFileId, personDto.getIdCardFront().getId()).build();
                personFiles.add(idCardFront);
            }
            if (personDto.getIdCardBack() != null) {
                BusinessRelateFile idCardBack = Builder.of(BusinessRelateFile.class)
                        .with(BusinessRelateFile::setBelongId, person.getId())
                        .with(BusinessRelateFile::setBelongType, ConstantUtil.ENTERPRISE_PERSON)
                        .with(BusinessRelateFile::setFileType, FileTypeEnum.IDENTITY_CARD_BACK.getCode())
                        .with(BusinessRelateFile::setFileId, personDto.getIdCardBack().getId()).build();
                personFiles.add(idCardBack);
            }
            if (CollUtil.isNotEmpty(personFiles)) {
                businessRelateFileBaseService.addBusinessRelateFiles(personFiles);
            }
        }
    }

    /**
     * 注册小图用户和企业
     * 
     * @param enterpriseDto
     * @param customerUser
     * @return
     */
    private void registerXiaotuUserAndEnterprise(EnterpriseDto enterpriseDto, CustomerUser customerUser) {
        // 注册小图用户
        String xtUid = customerUser.getXtUid();
        if (StrUtil.isEmpty(xtUid)) {
            UserInfoDto xtUserInfo = xiaotuRequestService.searchUserByUserName(customerUser.getPhoneNumber());
            if (xtUserInfo != null) {
                xtUid = xtUserInfo.getYhuuid1();
            } else {
                RegisterUserRequest registerUserRequest = new RegisterUserRequest();
                registerUserRequest.setXm(customerUser.getIdentifierNo());
                registerUserRequest.setYddh(customerUser.getPhoneNumber());
                registerUserRequest.setJsDm(getXtUserRole(enterpriseDto));
                RegisterUserResponse registerUserResponse = xiaotuRequestService.registerUser(registerUserRequest);
                xtUid = registerUserResponse.getYhuuid1();
            }
            customerUserService.bindXtUserId(customerUser.getId(), xtUid);
        }
        String xtEid = null;
        EnterpriseInfo enterpriseInfo = xiaotuRequestService.searchEnterprise(xtUid, enterpriseDto.getCertNo(), null);
        if (enterpriseInfo == null) {
            // 企业信息注册
            RegisterEnterpriseRequest registerEnterpriseRequest = new RegisterEnterpriseRequest();
            registerEnterpriseRequest.setHgqyDm(enterpriseDto.getCustomsEnterpriseCode());
            registerEnterpriseRequest.setNsrmc(enterpriseDto.getName());
            registerEnterpriseRequest.setNsrsbh(enterpriseDto.getTaxNo());
            registerEnterpriseRequest.setShxydm(enterpriseDto.getCertNo());
            registerEnterpriseRequest.setDqcode(enterpriseDto.getTaxAuthorityArea());
            registerEnterpriseRequest.setCktsqylxDm(enterpriseDto.getEnterpriseType());
            registerEnterpriseRequest.setYhuuid1(xtUid);
            registerEnterpriseRequest.setHstqysqbz(DictConstants.SYS_YES);
            registerEnterpriseRequest.setTsfwxybz(DictConstants.SYS_NO);
            RegisterEnterpriseResponse registerEnterpriseResponse = xiaotuRequestService
                    .registerEnterprise(registerEnterpriseRequest);
            xtEid = registerEnterpriseResponse.getSbqyuuid();
        } else {
            xtEid = enterpriseInfo.getSbqyuuid();
            // 海关代码、税号、主管税务机关、企业类型有变更，则更新
            if (!StrUtil.equals(enterpriseDto.getTaxNo(), enterpriseInfo.getNsrsbh())
                    || !StrUtil.equals(enterpriseDto.getCustomsEnterpriseCode(), enterpriseInfo.getHgqyDm())
                    || !StrUtil.equals(enterpriseDto.getTaxAuthorityArea(), enterpriseInfo.getDqcode())
                    || !StrUtil.equals(enterpriseDto.getEnterpriseType(), enterpriseInfo.getCktsqylxDm())) {
                UpdateEnterpriseRequest updateEnterpriseRequest = new UpdateEnterpriseRequest();
                updateEnterpriseRequest.setSbqyuuid(xtEid);
                updateEnterpriseRequest.setHgqyDm(enterpriseDto.getCustomsEnterpriseCode());
                updateEnterpriseRequest.setNsrmc(enterpriseDto.getName());
                updateEnterpriseRequest.setNsrsbh(enterpriseDto.getTaxNo());
                updateEnterpriseRequest.setDqcode(enterpriseDto.getTaxAuthorityArea());
                updateEnterpriseRequest.setCktsqylxDm(enterpriseDto.getEnterpriseType());
                updateEnterpriseRequest.setYhuuid1(xtUid);
                updateEnterpriseRequest.setHstqysqbz(DictConstants.SYS_YES);
                updateEnterpriseRequest.setTsfwxybz(
                        (DictConstants.CONTRACT_STATUS_DONE.equals(enterpriseDto.getTaxRebateAgreementSignStatus())
                                && DictConstants.EXPORT_TYPE_SELF.equals(enterpriseDto.getExportType()))
                                        ? DictConstants.SYS_YES
                                        : DictConstants.SYS_NO);
                xiaotuRequestService.updateEnterprise(updateEnterpriseRequest);
            }
        }
        // 绑定小图企业ID
        enterpriseBaseService.lambdaUpdate().set(Enterprise::getXtEid, xtEid)
                .eq(Enterprise::getId, enterpriseDto.getId()).update();
    }

    private String getXtUserRole(EnterpriseDto enterpriseDto) {
        switch (enterpriseDto.getEnterpriseType()) {
            case DictConstants.ENTERPRISE_TYPE_PRODUCE:
                return RegisterUserRequest.SCAntdQX;
            case DictConstants.ENTERPRISE_TYPE_PRODUCE_EXTERNAL:
                return RegisterUserRequest.QTSCAntd;
            case DictConstants.ENTERPRISE_TYPE_EXTERNAL_TRADE:
                return RegisterUserRequest.WMAntdQX;
            default:
                return RegisterUserRequest.QTAntdQX;
        }
    }
}
