package com.trade.service.contract.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.trade.service.contract.util.esign.bizprocess.BizProcessorFactory;
import com.trade.service.contract.util.esign.bizprocess.SignedBizProcessor;
import org.jsoup.helper.StringUtil;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.trade.common.constant.HttpStatus;
import com.trade.common.exception.ServiceException;
import com.trade.common.utils.StringUtils;
import com.trade.service.contract.constant.ContractConstant;
import com.trade.service.contract.dto.*;
import com.trade.service.contract.entity.ESignAccount;
import com.trade.service.contract.entity.ESignFile;
import com.trade.service.contract.entity.ESignFlow;
import com.trade.service.contract.entity.ESignFlowSigner;
import com.trade.service.contract.queue.MessageSender;
import com.trade.service.contract.service.*;
import com.trade.service.contract.util.esign.ESignConfig;
import com.trade.service.contract.util.esign.ESignConstant;
import com.trade.service.contract.util.esign.ESignRequest;
import com.trade.service.contract.util.esign.ESignTokenHelper;
import com.trade.service.contract.util.esign.entity.*;
import com.trade.service.filestorage.entity.TFileStorage;
import com.trade.service.filestorage.enums.FileModuleEnum;
import com.trade.service.filestorage.service.OSSFileService;
import com.trade.service.filestorage.service.TFileStorageService;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * E签宝合同签署流程
 */
@Slf4j
@Service(ContractConstant.CONTRACT_PLATFORM_SERVICE_NAME_ESIGN)
public class ESignContractServiceImpl implements SignPlatformService {

    @Resource
    private TFileStorageService fileStorageService;
    @Resource
    private OSSFileService ossFileService;
    @Resource
    private ESignAccountService esignAccountService;
    @Resource
    private ESignFlowService esignFlowService;
    @Resource
    private ESignFileService esignFileService;
    @Resource
    private ESignFlowSignerService esignFlowSignerService;
    @Resource
    private MessageSender messageSender;
    @Resource
    @Lazy
    private BizProcessorFactory bizProcessorFactory;

    @Override
    @Transactional
    public ContractSignOutput signContract(ContractSignInput signInput) {
        log.info("进入E签宝合同签署流程,业务场景:{},签署失效时长:{}hour", signInput.getBizScene(), signInput.getSignValidTime());
        ContractSignOutput output = new ContractSignOutput();
        // 创建签署流程
        String flowId = creatESignFlow(signInput);
        // 上传签署文件
        output.setItems(uploadSignFileAndSetPositions(flowId, signInput));
        // 发起签署流程
        startSignProcess(flowId);
        output.setFlowId(flowId);
        log.info("E签宝合同签署流程结束");
        return output;
    }

    @Override
    @Transactional
    public void handleCallback(ContractSignCallBack callback) {
        ESignFlow eSignFlow = esignFlowService.getByFlowId(callback.getFlowId());
        if (null == eSignFlow) {
            log.error("未查询到flowId对应的签署流程,flowId:{}", callback.getFlowId());
            return;
        }
        if (bizProcessorFactory == null || bizProcessorFactory.getProcessor(eSignFlow.getBizType()) == null) {
            log.info("当前服务未订阅该业务类型的电子签署回调通知,bizType:{}", eSignFlow.getBizType());
            return;
        }
        ESignProcessStatus eSignCallback = (ESignProcessStatus) callback;
        if (ESignConstant.ACTION_TYPE_FLOW_UPDATE.equals(eSignCallback.getAction())) {
            handleFlowUpdate(eSignFlow, eSignCallback);
            return;
        }
        if (ESignConstant.ACTION_TYPE_FLOW_FINISH.equals(eSignCallback.getAction())) {
            handleFlowFinish(eSignFlow, eSignCallback);
        }
    }

    @Override
    public Map<String, String> getAccountMap(List<ContractSignInfo> signInfoList) {
        // 将e签宝在中间步骤创建的逻辑提过来
        return null;
    }

    /**
     * 处理签署流程更新回调
     *
     * @param eSignFlow 签署流程记录
     * @param eSignCallback 签署流程回调信息
     */
    private void handleFlowUpdate(ESignFlow eSignFlow, ESignProcessStatus eSignCallback) {
        if (eSignFlow.getAutoArchive()) {
            log.info("流程自动归档，不处理流程更新回调");
            return;
        }
        ESignFlowSigner signer = esignFlowSignerService.getListByFlowId(eSignFlow.getFlowId()).stream()
                .filter(e -> e.getEAccountId().equals(eSignCallback.getAccountId())).findAny().orElse(null);
        if (null != signer && eSignCallback.getSignResult() == 2) {
            // 更新签署状态
            signer.setStatus(1);
            esignFlowSignerService.update(new UpdateWrapper<>(signer));
            // 通知业务系统
            Map<String, Object> params = new HashMap<>();
            params.put("flowId", eSignFlow.getFlowId());
            params.put("status", 2);
            messageSender.sendSignNotice2BizSys(JSON.toJSONString(params));
        }
        // todo 判断所有人签署完成，手动调用归档
    }

    /**
     * 处理签署流程完成回调
     * 
     * @param eSignFlow 签署流程记录
     * @param eSignCallback 签署流程回调信息
     */
    private void handleFlowFinish(ESignFlow eSignFlow, ESignProcessStatus eSignCallback) {
        if (ESignConstant.isFlowTerminate(eSignFlow.getStatus())) {
            log.info("流程已至终态，不处理流程回调");
            return;
        }
        // 签署完成
        if (ESignConstant.SIGN_FLOW_STATUS_FINISH == eSignCallback.getFlowStatus()) {
            // 归档签署文件
            /*
             * if (!eSignFlow.getAutoArchive()) { ESignRequest.archivESignFlow(eSignFlow.getFlowId()); }
             */
            // 下载签署完成后的文件
            downloadSignedFile(eSignFlow);
            // 更新签署流程状态
            esignFlowService.updateStatus(eSignFlow.getId(), ContractConstant.CONTRACT_SIGN_STATUS_SIGNED);
        } else if (ESignConstant.SIGN_FLOW_STATUS_OVERTIME == eSignCallback.getFlowStatus()) {
            // 过期签署流程
            esignFlowService.updateStatus(eSignFlow.getId(), ContractConstant.CONTRACT_SIGN_STATUS_EXPIRED);
        } else if (ESignConstant.SIGN_FLOW_STATUS_REFUSE == eSignCallback.getFlowStatus()) {
            // 拒签签署流程
            esignFlowService.updateStatus(eSignFlow.getId(), ContractConstant.CONTRACT_SIGN_STATUS_REJECTED);
        }
        // 通知 or invoke biz system
        noticeBizSysAfterSign(eSignFlow.getFlowId(), eSignFlow.getBizType(), eSignCallback.getEndTime());
    }

    /**
     * 流程结束后通知业务系统
     * 
     * @param flowId 签署流程id
     * @param bizType 业务类型
     */
    private void noticeBizSysAfterSign(String flowId, String bizType, LocalDateTime endTime) {
        SignedBizProcessor processor = bizProcessorFactory.getProcessor(bizType);
        SignCallback2Biz callback = initSignCallback2Biz(flowId, bizType, endTime);
        processor.process(callback);
        // 通知业务系统
        /*
         * Map<String, Object> params = new HashMap<>(); params.put("flowId", eSignFlow.getFlowId());
         * params.put("status", eSignFlow.getStatus()); messageSender.sendSignNotice2BizSys(JSON.toJSONString(params));
         */
    }

    private SignCallback2Biz initSignCallback2Biz(String flowId, String bizType, LocalDateTime endTime) {
        SignCallback2Biz callback = new SignCallback2Biz();
        callback.setSignFlowId(flowId);
        callback.setSignTime(endTime);
        callback.setBizType(bizType);
        ESignFlow eSignFlow = esignFlowService.getByFlowId(flowId);
        if (ContractConstant.CONTRACT_SIGN_STATUS_SIGNED.equals(eSignFlow.getStatus())) {
            List<ESignFile> eSignFileList = esignFileService.getByFlowId(flowId);
            List<SignCallback2Biz.SignedFile2Biz> signedFile2BizList = new ArrayList<>();
            for (ESignFile eSignFile : eSignFileList) {
                SignCallback2Biz.SignedFile2Biz file2Biz = new SignCallback2Biz.SignedFile2Biz();
                file2Biz.setFileId(eSignFile.getSignedFileId());
                file2Biz.setRawFileId(eSignFile.getRawFileId());
                file2Biz.setFileType(eSignFile.getFileType());
                signedFile2BizList.add(file2Biz);
            }
            callback.setSignedFiles(signedFile2BizList);
        }
        callback.setSignStatus(eSignFlow.getStatus());
        return callback;
    }

    /**
     * 下载已签署文件
     * 
     * @param eSignFlow 签署流程记录
     */
    private void downloadSignedFile(ESignFlow eSignFlow) {
        ESignTokenHelper.getTokenData();
        // 下载附件(流程归档后，下载签署后的文件。)
        List<ESignFileDownload> fileDownloadList = ESignRequest.downloadFlowDoc(eSignFlow.getFlowId(), null);
        List<ESignFile> eSignFileList = esignFileService.getByFlowId(eSignFlow.getFlowId());
        Map<String, ESignFile> eSignFileMap = eSignFileList.stream()
                .collect(Collectors.toMap(ESignFile::getEFileId, e -> e));
        for (ESignFileDownload fileDownload : fileDownloadList) {
            ESignFile eSignFile = eSignFileMap.get(fileDownload.getFileId());
            TFileStorage unsignedFile = fileStorageService.getById(eSignFile.getRawFileId());
            // 上传oss
            TFileStorage tFileStorage = ossFileService.downloadFileFromUrl(unsignedFile.getOriginalName(),
                    fileDownload.getFileUrl(), FileModuleEnum.SIGNED_CONTRACT);
            // 更新数据库
            esignFileService.lambdaUpdate().eq(ESignFile::getEFileId, eSignFile.getEFileId())
                    .set(ESignFile::getSignedFileId, tFileStorage.getId()).update();
        }
        log.info("e签宝签署完成文件下载完成,flowId:{}", eSignFlow.getFlowId());
    }

    /**
     * 获取本次签署所需创建的所有e签宝账号
     * </p>
     * ContractSignInfo 传值规则： </br>
     * 当多个签署文件只需要单方签署时，ContractSignInfo中只需设置singleSigner，sealInfoList中的signer可为空。</br>
     * 当多个签署文件需要多方签署时，ContractSignInfo中设置singleSigner可为空，设置sealInfoList的signer。</br>
     * 即:ContractSignInfo中的singleSigner为sealInfoList的signer的备选项。两者不可同时为空。</br>
     * sealInfoList数组中的ContractSeal对象中的sealIdType为企业证件类型时才需创建企业账号，否则为个人账号。</br>
     * 创建个人账号时只依赖ContractSigner信息，与ContractSeal无关。即需要加盖个人章时，只需设置ContractSigner信息即可。</br>
     *
     * @param signInfo 签署信息
     * @return <K 签署人证件号, V 签署人e签宝账号id>
     */
    private Map<String, String> creatESignAccount(ContractSignInfo signInfo) {
        // TODO check参数合法性
        Map<String, String> resultMap = new HashMap<>();
        // 单方签署
        ContractSigner signer = signInfo.getSingleSigner();
        if (null != signer) {
            resultMap.put(signer.getSignerIdNo(), creatPersonalAccount(signer));
        }
        signInfo.getSealInfoList().forEach(sealInfo -> {
            if (null == sealInfo.getSigner()) {// 签章信息中的签署人为空，则使用签署信息中的签署人
                if (null == signer) {
                    throw new ServiceException("签署信息中的签署人和签章信息中的签署人不能同时为空", HttpStatus.BAD_REQUEST);
                }
                sealInfo.setSigner(signer);
            } else {// 签署信息中的签署人不为空，则使用签署信息中的签署人creat个人账号
                resultMap.computeIfAbsent(sealInfo.getSigner().getSignerIdNo(),
                        o -> creatPersonalAccount(sealInfo.getSigner()));
            }
            // 若存在企业签章，则需创建企业账号
            if (ESignConstant.CRED_ORG_USCC.equals(sealInfo.getSealIdType())
                    || ESignConstant.CRED_ORG_UNKNOWN.equals(sealInfo.getSealIdType())) {
                resultMap.computeIfAbsent(sealInfo.getSealIdNo(), o -> createOrgAccount(sealInfo));
            }
        });
        return resultMap;
    }

    private String creatESignFlow(ContractSignInput signInput) {
        if (StringUtils.isEmpty(signInput.getBizScene())) {
            throw new ServiceException("签署任务-业务场景不能为空", HttpStatus.BAD_REQUEST);
        }
        // 构建签署流程配置
        ESignConfigInfo configInfo = new ESignConfigInfo(ESignConfig.ESign_NOTICE_DEVELOPER_URL, "1,2",
                ESignConfig.ESign_REDIRECT_URL, "1");
        // e签宝签约有效期（默认为24小时）
        // TODO 从配置中心获取
        Integer signValidity = 24;
        if (null != signInput.getSignValidTime()) {
            if (signInput.getSignValidTime() <= 0) {
                throw new ServiceException("签署任务-签署有效时间参数非法", HttpStatus.BAD_REQUEST);
            }
            signValidity = signInput.getSignValidTime();
        }
        LocalDateTime signValidityDate = LocalDateTime.now().plusHours(signValidity);// 签署有效期
        boolean autoArchive = null == signInput.getAutoArchive() || signInput.getAutoArchive();// 是否自动归档， 默认true
        ESignContractProcess process = new ESignContractProcess(autoArchive, signInput.getBizScene(), null, null,
                signValidityDate.toInstant(ZoneOffset.of("+8")).toEpochMilli(), null, null, configInfo);
        ESignTokenHelper.getTokenData();
        String flowId = ESignRequest.creatESignFlow(process);
        ESignFlow esignFlow = ESignFlow.builder().bizSysId(signInput.getBizSysId()).flowId(flowId)
                .scene(signInput.getBizScene()).expiredTime(signValidityDate).bizType(signInput.getBizType())
                .status(ContractConstant.CONTRACT_SIGN_STATUS_UNSIGNED).autoArchive(autoArchive).build();
        esignFlowService.add(esignFlow);
        return flowId;
    }

    private List<ContractSignOutputItem> uploadSignFileAndSetPositions(String flowId, ContractSignInput signInput) {
        List<ContractSignInfo> signInfos = signInput.getSigneInfoList();
        if (CollectionUtils.isEmpty(signInfos)) {
            throw new ServiceException("签署任务-待签署信息列表不能为空", HttpStatus.BAD_REQUEST);
        }
        // 意愿认证方式
        List<String> willTypes = CollectionUtils.isEmpty(signInput.getWillTypes()) ? ESignConfig.getWillTypes()
                : signInput.getWillTypes();
        List<ESignDoc> signFieldList = new ArrayList<>();
        List<ContractSignOutputItem> outputItems = new ArrayList<>();
        for (ContractSignInfo signInfo : signInfos) {
            if (null == signInfo.getFileId()) {
                throw new ServiceException("签署任务-待签署文件ID不能为空", HttpStatus.BAD_REQUEST);
            }
            // 上传签署文件
            String eSignFileId = uploadSignFile(flowId, signInfo);
            // 设置签署位置
            addSignField(signFieldList, flowId, signInfo, eSignFileId, willTypes);
            outputItems.add(new ContractSignOutputItem(signInfo.getFileType(), signInfo.getFileId(), eSignFileId));
        }
        ESignRequest.addSignerHandSignArea(flowId, signFieldList);
        return outputItems;
    }

    /**
     * 添加签署位置
     *
     * @param signFieldList 签署文档列表
     * @param signInfo 签章信息
     * @param eSignFileId e签宝文件id
     */
    private void addSignField(List<ESignDoc> signFieldList, String flowId, ContractSignInfo signInfo,
            String eSignFileId, List<String> willTypes) {
        List<ContractSeal> sealInfoList = signInfo.getSealInfoList();
        if (CollectionUtils.isEmpty(sealInfoList)) {
            throw new ServiceException("签署任务-签章信息列表不能为空", HttpStatus.BAD_REQUEST);
        }
        // 先统一创建账号，有任意创建失败则直接失败，不再进行后续操作
        Map<String, String> accountMap = creatESignAccount(signInfo);
        for (ContractSeal salInfo : sealInfoList) {
            // 签章里的签署人信息未传，则使用签署信息中的签署人信息
            ContractSigner signer = null == salInfo.getSigner() ? signInfo.getSingleSigner() : salInfo.getSigner();
            ESignDocPosition posBean = ESignRequest.searchWordsPosition(flowId, eSignFileId, salInfo.getKeyword());
            if (Boolean.TRUE.equals(salInfo.getWithTime())) {
                posBean.setAddSignTime(true);
                posBean.setSignTimeFormat(ESignConstant.SIGN_DATE_FORMAT);
            }
            ESignDoc signField = null;
            // 企业
            if (ESignConstant.CRED_ORG_USCC.equals(salInfo.getSealIdType())
                    || ESignConstant.CRED_ORG_UNKNOWN.equals(salInfo.getSealIdType())) {
                // 机构签约类别，当签约主体为机构时必传
                String actorIdentityType = "2";// 企业
                if (Boolean.TRUE.equals(salInfo.getSignLegal())) {
                    actorIdentityType = "3";// 企业法人章
                }
                signField = new ESignDoc(eSignFileId, accountMap.get(signer.getSignerIdNo()), actorIdentityType,
                        accountMap.get(salInfo.getSealIdNo()), null, 1, posBean, null, null, null);
            } else if (ESignConstant.CRED_PSN_CH_IDCARD.equals(signer.getSignerIdType())
                    || ESignConstant.CRED_PSN_PASSPORT.equals(signer.getSignerIdType())) {
                        signField = new ESignDoc(eSignFileId, accountMap.get(signer.getSignerIdNo()), null, null, null,
                                1, posBean, "1", null, null);
                    }
            if (null == signField) {
                log.error("签署任务-获取签章位置出错fileId:{},sealIdType:{},keyword:{}", signInfo.getFileId(),
                        salInfo.getSealIdType(), salInfo.getKeyword());
                throw new ServiceException("签署任务-获取签章位置出错，请检查签章传参是否正确", HttpStatus.ERROR);
            }
            signField.setWillTypes(willTypes);
            signFieldList.add(signField);
        }
        // 保存 流程签署方记录表
        saveSignFlowSigner(flowId, accountMap);
    }

    private void saveSignFlowSigner(String flowId, Map<String, String> accountMap) {
        for (String eAccountId : accountMap.values()) {
            ESignFlowSigner flowSigner = ESignFlowSigner.builder().flowId(flowId).eAccountId(eAccountId).build();
            esignFlowSignerService.add(flowSigner);
        }
    }

    /**
     * 上传签署文件
     *
     * @param flowId 流程id
     * @param signInfo 签署信息
     * @return e签宝文件id
     */
    private String uploadSignFile(String flowId, ContractSignInfo signInfo) {
        TFileStorage fileStorage = fileStorageService.getFileStorageById(signInfo.getFileId());
        String fileName = fileStorage.getName();
        String eSignFileId;
        try (InputStream inputStream = ossFileService.getFileInputStream(fileStorage.getPath())) {
            if (null == inputStream) {
                throw new ServiceException("签署任务-获取待签署文件失败", HttpStatus.BAD_REQUEST);
            }
            JSONObject jsonObject = ESignRequest.createFileByUpload(inputStream, fileName, fileStorage.getSize());
            eSignFileId = jsonObject.getString("fileId");
            String uploadUrl = jsonObject.getString("uploadUrl");
            // 文件流上传文件
            ESignRequest.streamUpload(inputStream, uploadUrl);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ServiceException("签署任务- 上传签署文件失败", HttpStatus.BAD_REQUEST);
        }
        ESignRequest.addFlowDoc(flowId, Collections.singletonList(new ESignContractDoc(eSignFileId, fileName)));
        ESignFile esignFile = ESignFile.builder().flowId(flowId).eFileId(eSignFileId).fileName(fileName)
                .rawFileId(signInfo.getFileId()).fileType(signInfo.getFileType()).build();
        esignFileService.add(esignFile);
        return eSignFileId;
    }

    /**
     * 创建个人账号
     *
     * @param signer 个人信息
     * @return 个人账号ID
     */
    private String creatPersonalAccount(ContractSigner signer) {
        if (null == signer || StrUtil.isBlank(signer.getSigner()) || StrUtil.isBlank(signer.getSignerIdType())
                || StrUtil.isBlank(signer.getSignerIdNo())
                || (StrUtil.isBlank(signer.getMobile()) && StringUtil.isBlank(signer.getEmail()))) {
            log.error(JSON.toJSONString(signer));
            throw new ServiceException("个人账户信息不全！", HttpStatus.BAD_REQUEST);
        }
        String signPersonAccountId;
        // 查询持久层是否存在该签署人账号，若有，若本次信息与e签宝端不符则更新e签宝端账号信息；若无，则请求查询e签宝系统，若e签宝系统存在则不用重新再创建账号，否则请求e签宝新增账号
        ESignAccount oldPersonalAccount = new ESignAccount();
        // 根据证件号查询
        ESignAccount historicAccount = esignAccountService.getESignSignerInfoByIdNo(signer.getSignerIdNo());
        if (null == historicAccount) {
            String thirdPartyUserId = ESignConfig.getPersonThirdPartyUserId(signer.getSignerIdNo());
            ESignPersonAccountResponse remotePersonalAccount = ESignRequest.qryPersonAcctByThirdId(thirdPartyUserId);
            ESignPersonAccount personalAccount = new ESignPersonAccount(signer);
            if (null != remotePersonalAccount) {// e签宝已存在该签署人账号
                signPersonAccountId = remotePersonalAccount.getAccountId();
                oldPersonalAccount.setName(remotePersonalAccount.getName());
                oldPersonalAccount.setIdType(remotePersonalAccount.getIdType());
                oldPersonalAccount.setIdNo(remotePersonalAccount.getIdNumber());
                oldPersonalAccount.setPhone(remotePersonalAccount.getMobile());
                oldPersonalAccount.setEmail(remotePersonalAccount.getEmail());
                esignAccountService.add(new ESignAccount(personalAccount, signPersonAccountId));
            } else {
                signPersonAccountId = ESignRequest.createPersonAcctId(personalAccount);
                // 持久化
                esignAccountService.add(new ESignAccount(personalAccount, signPersonAccountId));
                return signPersonAccountId;
            }
        } else {
            oldPersonalAccount.setName(historicAccount.getName());
            oldPersonalAccount.setIdType(historicAccount.getIdType());
            oldPersonalAccount.setIdNo(historicAccount.getIdNo());
            oldPersonalAccount.setPhone(historicAccount.getPhone());
            oldPersonalAccount.setEmail(historicAccount.getEmail());
            signPersonAccountId = historicAccount.getEAccountId();
        }
        // 注意：我们系统请求E签宝创建个人帐号时“签署人姓名、签署人手机号”必须有值，“签署人邮箱”是选传的
        if (!signer.getSigner().equals(oldPersonalAccount.getName())
                || (StrUtil.isNotBlank(signer.getMobile()) && !signer.getMobile().equals(oldPersonalAccount.getPhone()))
                || (StrUtil.isNotBlank(signer.getEmail())
                        && !signer.getEmail().equals(oldPersonalAccount.getEmail()))) {
            ESignPersonAccountUpdate personUpdate = new ESignPersonAccountUpdate();
            personUpdate.setAccountId(signPersonAccountId);
            personUpdate.setIdNumber(signer.getSignerIdNo());
            personUpdate.setName(signer.getSigner());
            if (StrUtil.isNotBlank(signer.getMobile())) {
                personUpdate.setMobile(signer.getMobile());
            }
            if (StrUtil.isNotBlank(signer.getEmail())) {
                personUpdate.setEmail(signer.getEmail());
            }
            ESignRequest.updatePersonAcctByAcctId(personUpdate);
            esignAccountService.updateById(oldPersonalAccount);
        }
        return signPersonAccountId;
    }

    /**
     * 创建企业账号
     *
     * @param sealInfo 签章信息
     * @return 企业账号ID
     */
    private String createOrgAccount(ContractSeal sealInfo) {
        if (null == sealInfo || StrUtil.isBlank(sealInfo.getSealName()) || StrUtil.isBlank(sealInfo.getSealIdNo())) {
            log.error(JSON.toJSONString(sealInfo));
            throw new ServiceException("机构帐号信息不全！", HttpStatus.BAD_REQUEST);
        }
        String signOrgAccountId;
        // 查询持久层是否存在该签署人账号，若有，若本次信息与e签宝端不符则更新e签宝端账号信息；若无，则请求查询e签宝系统，若e签宝系统存在则不用重新再创建账号，否则请求e签宝新增账号
        ESignAccount oldOrgAccount = new ESignAccount();
        ESignAccount historicAccount = esignAccountService.getESignSignerInfoByIdNo(sealInfo.getSealIdNo());
        if (null == historicAccount) {
            String thirdPartyUserId = ESignConfig.getOrgThirdPartyUserId(sealInfo.getSealIdNo(),
                    sealInfo.getSealIdType());
            ESignOrganAccount esignOrganAccount = new ESignOrganAccount(sealInfo);
            ESignOrganAccountResponse remoteOrgAccount = ESignRequest.qryOrgAcctByThirdId(thirdPartyUserId);
            if (null != remoteOrgAccount) {
                signOrgAccountId = remoteOrgAccount.getOrgId();
                oldOrgAccount.setName(remoteOrgAccount.getName());
                oldOrgAccount.setIdNo(remoteOrgAccount.getIdNumber());
                esignAccountService.add(new ESignAccount(esignOrganAccount, signOrgAccountId));
            } else {
                signOrgAccountId = ESignRequest.createOrgAcctId(esignOrganAccount);
                // 持久化
                esignAccountService.add(new ESignAccount(esignOrganAccount, signOrgAccountId));
                return signOrgAccountId;
            }
        } else {
            oldOrgAccount.setName(historicAccount.getName());
            signOrgAccountId = historicAccount.getEAccountId();
        }
        // 注意：我们系统请求E签宝创建机构帐号时“机构名称”必须有值，“企业法定代表人身份证号、企业法定代表人名称”是选传的
        if (!sealInfo.getSealName().equals(oldOrgAccount.getName())) {
            ESignOrganAccountUpdate orgUpdate = new ESignOrganAccountUpdate();
            orgUpdate.setOrgId(signOrgAccountId);
            orgUpdate.setName(sealInfo.getSealName());
            ESignRequest.updateOrgAcctByOrgId(orgUpdate);
        }
        return signOrgAccountId;
    }

    private void startSignProcess(String flowId) {
        ESignRequest.startSignFlow(flowId);
    }
}
