package com.sifang.modules.esign.service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.sifang.modules.config.EsignConfig;
import com.sifang.modules.contract.entity.TraderContractTemplate;
import com.sifang.modules.customer.entity.CrmCustomerContractManagement;
import com.sifang.modules.esign.cn.tsign.hz.comm.EsignHttpHelper;
import com.sifang.modules.esign.cn.tsign.hz.comm.EsignHttpResponse;
import com.sifang.modules.esign.cn.tsign.hz.enums.EsignRequestType;
import com.sifang.modules.esign.cn.tsign.hz.exception.EsignDemoException;
import com.sifang.modules.esign.constants.ESignConstants;
import com.sifang.modules.sunshine.SystemSetting.entity.CrmTrader;
import com.sifang.modules.sunshine.SystemSetting.entity.ProjectCompanySettings;
import com.sifang.modules.sunshine.SystemSetting.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ESignSignService {

    private static Logger logger= LoggerFactory.getLogger(ESignSignService.class);

    private static String eSignHost= EsignConfig.EsignHost;
    private static String eSignAppId=EsignConfig.EsignAppId;
    private static String eSignAppSecret=EsignConfig.EsignAppSecret;


    /**
     * 获取签章区位置
     */
    public static List<Map<String,Object>>  getKeywordPositions(String fileId,String keyWard) throws EsignDemoException {
        String apiaddr = "/v3/files/"+fileId+"/keyword-positions";
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        Gson gson=new Gson();
        Map<String,Object> map=new HashMap<>();
        List<String> keyWards=new ArrayList<>();
        List<Map<String,Object>> list = Lists.newArrayList();
        keyWards.add(keyWard);
        map.put("keywords",keyWards); // 关键字
        String jsonParm=gson.toJson(map);
        //请求方法
        EsignRequestType requestType= EsignRequestType.POST;
        //生成签名鉴权方式的的header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId,eSignAppSecret,jsonParm,requestType.name(),apiaddr,true);
        //发起接口请求
        EsignHttpResponse response=EsignHttpHelper.doCommHttp(eSignHost, apiaddr,requestType , jsonParm, header,true);
        logger.info(">>>>>>>>>>>>>>>>>>>getKeywordPositions httpResponse:{},data:{} ",response.getStatus(),response.getBody());
        JsonObject getKeywordPositions = gson.fromJson(response.getBody(), JsonObject.class);
        if(ESignConstants.SUCCESS.equals(getKeywordPositions.get("code").getAsString())){
            JsonArray keywordArray = getKeywordPositions.getAsJsonObject("data").get("keywordPositions").getAsJsonArray();
            logger.info(">>>>>>>>>>>>>>>getKeywordPositions keywordArray:{}",keywordArray);
            JsonArray positions =keywordArray.get(0).getAsJsonObject().getAsJsonArray("positions");
            for(int i=0;i<positions.size();i++){
                Map<String,Object> remap=new HashMap<>();
                logger.info(">>>>>>>>>>>>>>>getKeywordPositions positions:{}",positions);
                if(positions!=null && positions.size()>0){
                    Integer pageNum= positions.get(i).getAsJsonObject().get("pageNum").getAsInt();
                    remap.put("pageNum", pageNum);
                    JsonArray coordinates =positions.get(i).getAsJsonObject().getAsJsonArray("coordinates");
                    logger.info(">>>>>>>>>>>>>>>getKeywordPositions coordinates:{}",coordinates);
                    JsonObject object=coordinates.get(0).getAsJsonObject();
                    remap.put("positionX",object.get("positionX").getAsFloat());
                    remap.put("positionY",object.get("positionY").getAsFloat());
                    logger.info(">>>>>>>>>>>>>>>getKeywordPositions object:{} ",object);
                    list.add(remap);
                }else{
                    throw new EsignDemoException("未找到“"+keyWard+"”关键字位置!");
                }
            }
        }else{
            throw new EsignDemoException("获取定位失败!失败原因:"+getKeywordPositions.get("message"));
        }
        return list;
    }

    /**
     * 发起签署(代理商合同)
     * @return 返回 signFlowId 签署流程ID
     */
    public static String createByFile(String fileId, String fileName, CrmTrader trader,String agentId,String userId) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 设置待签署文件信息
        Map<String,Object> docs=new HashMap<>();
        docs.put("fileId",fileId);
        docs.put("fileName",fileName);
        // 签署流程配置项
        Map<String,Object> signFlowConfig=new HashMap<>();
        signFlowConfig.put("signFlowTitle", "合同签署"); //签署流程主题
        signFlowConfig.put("autoStart", true); //自动开启签署流程，默认值 true    false - 非自动开启 需调用【开启签署流程】接口后流程进入“签署中”状态
        signFlowConfig.put("autoFinish",true);  //所有签署方签署完成后流程自动完结，默认值 false  true - 自动完结   false - 非自动完结，需调用【完结签署流程】接口完结
        signFlowConfig.put("notifyUrl",EsignConfig.NotifyUrl+"/a/main/sign/companySignCallBack");   //接收相关回调通知的Web地址
        Map<String,Object> signConfig=new HashMap<>();  // 签署配置项
        signConfig.put("availableSignClientTypes","1");  //签署终端类型，默认值1和2（英文逗号分隔）   1 - 网页（自适配H5/PC样式），2 - 支付宝
        signFlowConfig.put("signConfig",signConfig);
        Map<String,Object> redirectConfig=new HashMap<>();
        redirectConfig.put("redirectUrl",EsignConfig.NotifyUrl+"/a/main/redirect/eSignSuccess");  // 签署完成后跳转页面（需符合 https /http 协议地址）
        signFlowConfig.put("redirectConfig",redirectConfig);

        Map<String, Object> noticeConfig = new HashMap<>();
        noticeConfig.put("noticeTypes","1");
        signFlowConfig.put("noticeConfig",noticeConfig);
       /* //签署流程的发起方
        Map<String,Object> signFlowInitiator=new HashMap<>();
        Map<String,Object> transactor=new HashMap<>(); //机构发起方的经办人
        transactor.put("psnId","");  //经办人账号ID
        Map<String,Object> orgInitiator=new HashMap<>();
        orgInitiator.put("orgId",""); //机构账号ID
        orgInitiator.put("transactor",transactor); //机构发起方的经办人
        signFlowInitiator.put("orgInitiator",orgInitiator);*/
        //签署方信息
        Map<String,Object> signers=new HashMap<>();
      /*  signers.put("noticeConfig", noticeConfig);*/

        signers.put("signerType", 1);
        Map<String,Object> signConfig2=new HashMap<>();
        signConfig2.put("signOrder",1);
        signers.put("signConfig", signConfig2);
        Map<String,Object> orgSignerInfo=new HashMap<>();  //机构签署方信息
        orgSignerInfo.put("orgName", trader.getName());   //机构名称
        Map<String,Object> transactorInfo=new HashMap<>();  // 机构经办人信息
        transactorInfo.put("psnAccount", trader.getMobile());   //经办人账号标识，手机号或邮箱
        orgSignerInfo.put("transactorInfo",transactorInfo);
        List<Map<String,Object>> signFieldsArray=new ArrayList<>();
        List<Map<String,Object>> posisitons=getKeywordPositions(fileId,"乙方公章");
        for(Map<String,Object> posisiton:posisitons){
            Map<String,Object> signFieldPosition=new HashMap<>(); // 签章区位置信息
            Map<String,Object> signFields=new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
            signFields.put("fileId", fileId);    // 签署区所在待签署文件ID
            signFields.put("customBizNum", agentId);  // 开发者自定义业务编号
            Map<String,Object> normalSignFieldConfig=new HashMap<>(); //签章区配置项
            normalSignFieldConfig.put("freeMode", false);  // 是否自由签章，默认值 false
            normalSignFieldConfig.put("assignedSealId", "");  // 指定印章ID
            normalSignFieldConfig.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
            normalSignFieldConfig.put("movableSignField", true);   //页面是否可移动签章区，默认值 false
            signFieldPosition.put("positionX", posisiton.get("positionX"));   //签章区所在X坐标
            signFieldPosition.put("positionY", posisiton.get("positionY"));   //签章区所在Y坐标
            signFieldPosition.put("positionPage", posisiton.get("pageNum"));

            normalSignFieldConfig.put("signFieldPosition",signFieldPosition);
            signFields.put("normalSignFieldConfig", normalSignFieldConfig);
            signFieldsArray.add(signFields);
        }
        signers.put("orgSignerInfo", orgSignerInfo);
        signers.put("signFields",signFieldsArray);


        Map<String,Object> param=new HashMap<>();
        List<Map<String,Object>> docsArray=new ArrayList<>();
        docsArray.add(docs);
        param.put("docs", docsArray);
        param.put("signFlowConfig", signFlowConfig);

        List<Map<String,Object>> signersArray=new ArrayList<>();
        signersArray.add(signers);


        //丙方 实控人签署
        Map<String,Object> signers2=new HashMap<>();

        signers2.put("noticeConfig", noticeConfig);

        signers2.put("signerType", 0);
        Map<String,Object> signConfig3=new HashMap<>();
        signConfig3.put("signOrder",2);
        signers2.put("signConfig", signConfig3);
        Map<String,Object> psnSignerInfo=new HashMap<>();  //个人签署方信息
        psnSignerInfo.put("psnAccount", trader.getTelephone());   //机构名称
        Map<String,Object> psnInfo=new HashMap<>();  //
        psnInfo.put("psnMobile", trader.getTelephone());
        psnInfo.put("psnName", trader.getActualContacts());//实控人
        psnInfo.put("psnIDCardNum", trader.getActualIdCode());//实控人身份证号
        psnSignerInfo.put("psnInfo",psnInfo);
        List<Map<String,Object>> signFieldsArray4=new ArrayList<>();
        List<Map<String,Object>> posisi4=getKeywordPositions(fileId,"签字：");
        for(Map<String,Object> posisiton:posisi4){
            Map<String,Object> signFieldPosition=new HashMap<>(); // 签章区位置信息
            Map<String,Object> signFields=new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
            signFields.put("fileId", fileId);    // 签署区所在待签署文件ID
            signFields.put("customBizNum", agentId);  // 开发者自定义业务编号
            Map<String,Object> normalSignFieldConfig=new HashMap<>(); //签章区配置项
            normalSignFieldConfig.put("freeMode", false);  // 是否自由签章，默认值 false
            normalSignFieldConfig.put("assignedSealId", "");  // 指定印章ID
            normalSignFieldConfig.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
            normalSignFieldConfig.put("movableSignField", true);   //页面是否可移动签章区，默认值 false
            signFieldPosition.put("positionX", posisiton.get("positionX"));   //签章区所在X坐标
            signFieldPosition.put("positionY", posisiton.get("positionY"));   //签章区所在Y坐标
            signFieldPosition.put("positionPage", posisiton.get("pageNum"));

            normalSignFieldConfig.put("signFieldPosition",signFieldPosition);
            signFields.put("normalSignFieldConfig", normalSignFieldConfig);
            signFieldsArray4.add(signFields);
        }
        signers2.put("psnSignerInfo", psnSignerInfo);
        signers2.put("signFields",signFieldsArray4);
        signersArray.add(signers2);

        //甲方--签署方信息
        Map<String,Object> signersjia=new HashMap<>();

        signersjia.put("noticeConfig", noticeConfig);
        signersjia.put("signerType", 1);
        Map<String,Object> signConfigjia=new HashMap<>();
        signConfigjia.put("signOrder",3);
        signersjia.put("signConfig", signConfigjia);
        Map<String,Object> orgSignerInfojia=new HashMap<>();  //机构签署方信息
        orgSignerInfojia.put("orgName", "天津七道工程有限公司");   //机构名称
        Map<String,Object> jiaInfo=new HashMap<>();  // 机构经办人信息
        jiaInfo.put("psnAccount", "15201240520");   //经办人账号标识，手机号或邮箱
        orgSignerInfojia.put("transactorInfo",jiaInfo);
        List<Map<String,Object>> signFieldsArrayjia=new ArrayList<>();
        List<Map<String,Object>> posisitonsjia=getKeywordPositions(fileId,"甲方公章");
        for(Map<String,Object> posisiton:posisitonsjia){
            Map<String,Object> signFieldPosition=new HashMap<>(); // 签章区位置信息
            Map<String,Object> signFields=new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
            signFields.put("fileId", fileId);    // 签署区所在待签署文件ID
            signFields.put("customBizNum", "zhonglingQS");  // 开发者自定义业务编号
            Map<String,Object> normalSignFieldConfig=new HashMap<>(); //签章区配置项
            normalSignFieldConfig.put("freeMode", false);  // 是否自由签章，默认值 false
            normalSignFieldConfig.put("assignedSealId", "");  // 指定印章ID
            normalSignFieldConfig.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
            normalSignFieldConfig.put("movableSignField", true);   //页面是否可移动签章区，默认值 false
            signFieldPosition.put("positionX", posisiton.get("positionX"));   //签章区所在X坐标
            signFieldPosition.put("positionY", posisiton.get("positionY"));   //签章区所在Y坐标
            signFieldPosition.put("positionPage", posisiton.get("pageNum"));

            normalSignFieldConfig.put("signFieldPosition",signFieldPosition);
            signFields.put("normalSignFieldConfig", normalSignFieldConfig);
            signFieldsArrayjia.add(signFields);
        }
        signersjia.put("orgSignerInfo", orgSignerInfojia);
        signersjia.put("signFields",signFieldsArrayjia);
        signersArray.add(signersjia);

        param.put("signers",signersArray);
        Gson gson=new Gson();
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = gson.toJson(param);
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>createByFile jsonParam:{}",jsonParm);
        //请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        //生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId, eSignAppSecret, jsonParm, requestType.name(), apiaddr, true);
        //发起接口请求
        EsignHttpResponse createByFile=EsignHttpHelper.doCommHttp(eSignHost, apiaddr, requestType, jsonParm, header, true);
        logger.info("?>>>>>>>>>>>>>>>>>>>>>>>>>>createByFile createByFile.getBody:{},status:{}",createByFile.getBody(),createByFile.getStatus());
        JsonObject createByFileJsonObject = gson.fromJson(createByFile.getBody(), JsonObject.class);
        if(ESignConstants.SUCCESS.equals(createByFileJsonObject.get("code").getAsString())){
            JsonObject createByFileData = createByFileJsonObject.getAsJsonObject("data");
            String signFlowId = createByFileData.get("signFlowId").getAsString();   // 签署流程ID
            logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>createByFile  流程id:"+signFlowId);
            return signFlowId;
        }else{
            throw new EsignDemoException("发起签署失败!失败原因:"+createByFileJsonObject.get("message"));
        }
    }



    /**
     * 发起签署 （农户合同-华融）
     *
     * @return 返回 signFlowId 签署流程ID
     */
    public static String createTentConcatByFile(String fileId, String fileName, CrmCustomerContractManagement contractManagement,
                                      String signFlowTitle, ProjectCompanySettings companySettings,String bpMobile ,TraderContractTemplate template) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/create-by-file";
        // 设置待签署文件信息
        List<Map<String, Object>> docs = new ArrayList<>();
        Map<String, Object> doc = new HashMap<>();
        doc.put("fileId", fileId);
        doc.put("fileName", fileName);
        docs.add(doc);
        // 签署流程配置项
        Map<String, Object> signFlowConfig = new HashMap<>();
        signFlowConfig.put("signFlowTitle", signFlowTitle); //签署流程主题
        signFlowConfig.put("autoStart", true); //自动开启签署流程，默认值 true    false - 非自动开启 需调用【开启签署流程】接口后流程进入“签署中”状态
        signFlowConfig.put("autoFinish", true);  //所有签署方签署完成后流程自动完结，默认值 false  true - 自动完结   false - 非自动完结，需调用【完结签署流程】接口完结
        signFlowConfig.put("notifyUrl", EsignConfig.NotifyUrl+"/a/main/sign/signTentContractCallback");   //接收相关回调通知的Web地址
        Map<String, Object> redirectConfig = new HashMap<>();
        redirectConfig.put("redirectUrl", EsignConfig.NotifyUrl+"/a/main/redirect/eSignSuccess");  // 签署完成后跳转页面（需符合 https /http 协议地址）
        signFlowConfig.put("redirectConfig", redirectConfig);
        Map<String, Object> noticeConfig = new HashMap<>();
        noticeConfig.put("noticeTypes","");  //通知类型，通知发起方、签署方、抄送方，默认不通知（值为""空字符串）
        signFlowConfig.put("noticeConfig",noticeConfig);
        //签署流程的发起方
        Map<String, Object> signFlowInitiator = new HashMap<>();
        Map<String, Object> transactor = new HashMap<>(); //机构发起方的经办人
        transactor.put("psnId", companySettings.getPsnId());  //经办人账号ID
        Map<String, Object> orgInitiator = new HashMap<>();
        orgInitiator.put("orgId", companySettings.getSignerCode()); //机构账号ID
        orgInitiator.put("transactor", transactor); //机构发起方的经办人
        signFlowInitiator.put("orgInitiator", orgInitiator);
        //签署方信息 双方签署
        // 平台方信息
        List<Map<String, Object>> signers = new ArrayList<>();
        Map<String, Object> signerO = new HashMap<>();
        Map<String, Object> signConfigO = new HashMap<>();
        signConfigO.put("signOrder", 1);
        signConfigO.put("signTaskType","0");
        signerO.put("signConfig", signConfigO);

        signerO.put("signerType", 1);


        // 平台多个签署区，单页签章设置开始-------->
        Map<String, Object> signFieldO = new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
        signFieldO.put("fileId", fileId);    // 签署区所在待签署文件ID
        signFieldO.put("customBizNum", contractManagement.getId());  // 开发者自定义业务编号
        Map<String, Object> normalSignFieldConfigO = new HashMap<>(); //签章区配置项
        normalSignFieldConfigO.put("autoSign",true); //后台自动落章（无感知）

        normalSignFieldConfigO.put("freeMode", false);  // 是否自由签章，默认值 false
        normalSignFieldConfigO.put("assignedSealId", companySettings.getSealId());  // 指定印章ID
        normalSignFieldConfigO.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
        normalSignFieldConfigO.put("movableSignField", true);   //页面是否可移动签章区，默认值 false

        //公司盖章的地方关键字
        List<Map<String, Object>> posisitons = getKeywordPositions(fileId, "乙方（盖章）:");
        Map<String, Object> posisitonO = null;
        if(posisitons.size()>0){
            posisitonO=posisitons.get(0);
        }
        Map<String, Object> signFieldPositionO = new HashMap<>(); // 签章区位置信息
        if(posisitonO!=null){
            signFieldPositionO.put("positionX", (Float)posisitonO.get("positionX")+100f);   //签章区所在X坐标
            signFieldPositionO.put("positionY", posisitonO.get("positionY"));   //签章区所在Y坐标
            signFieldPositionO.put("positionPage", posisitonO.get("pageNum"));
        }
        normalSignFieldConfigO.put("signFieldPosition", signFieldPositionO);
        signFieldO.put("normalSignFieldConfig", normalSignFieldConfigO);


        List<Map<String, Object>> signFieldsO = new ArrayList<>();
        signFieldsO.add(signFieldO);
        signerO.put("signFields", signFieldsO);

        // 用户信息
        Map<String, Object> signerP = new HashMap<>();
        Map<String, Object> signConfigP = new HashMap<>();
        signConfigP.put("signOrder", 2);
        signConfigP.put("signTaskType","0");
        signerP.put("signerType", 0);

        Map<String, Object> psnSignerInfo = new HashMap<>();  //个人签署方信息
        psnSignerInfo.put("psnAccount", contractManagement.getTenantMobile());   // 个人账号标识（手机号或邮箱）
        signerP.put("psnSignerInfo", psnSignerInfo);

        Map<String, Object> signFieldP = new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
        signFieldP.put("fileId", fileId);    // 签署区所在待签署文件ID
        signFieldP.put("customBizNum", "");  // 开发者自定义业务编号
        signerP.put("signConfig", signConfigP);

        Map<String, Object> normalSignFieldConfigP = new HashMap<>(); //签章区配置项
        normalSignFieldConfigP.put("freeMode", false);  // 是否自由签章，默认值 false

        // 页面可选个人印章样式，默认值0和1（英文逗号分隔）0 - 手写签名 1 - 姓名印章 2 - 手写签名AI校验
        normalSignFieldConfigP.put("psnSealStyles", "0");

        normalSignFieldConfigP.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
        normalSignFieldConfigP.put("movableSignField", false);   //页面是否可移动签章区，默认值 false

        //农户签章的地方关键字
        List<Map<String, Object>> posisitony = getKeywordPositions(fileId, template.getSignKey());
        Map<String, Object> posisitonP = null;
        Map<String, Object> signFieldPositionP = new HashMap<>(); // 签章区位置信息
        if(template.getPositionPage()!=null){
            signFieldPositionP.put("positionX", template.getPositionAcross());   //签章区所在X坐标
            signFieldPositionP.put("positionY", template.getPositionVertical());   //签章区所在Y坐标
            signFieldPositionP.put("positionPage",template.getPositionPage());
        }else {
            if(posisitony.size()>0){
                posisitonP=posisitony.get(0);
                if(template.getSignKey().contains("电子签名")){
                    signFieldPositionP.put("positionX",  (Float)posisitonP.get("positionX")+150f);   //签章区所在X坐标
                }else{
                    signFieldPositionP.put("positionX",  (Float)posisitonP.get("positionX")+110f);   //签章区所在X坐标
                }
                signFieldPositionP.put("positionY", posisitonP.get("positionY"));   //签章区所在Y坐标
                signFieldPositionP.put("positionPage", posisitonP.get("pageNum"));
            }
        }

        normalSignFieldConfigP.put("signFieldPosition", signFieldPositionP);
       signFieldP.put("normalSignFieldConfig", normalSignFieldConfigP);

        Map<String, Object> dateSignFieldConfig = new HashMap<>(); //独立签署日期配置项
        dateSignFieldConfig.put("dateFormat", "yyyy年MM月dd日");  // 日期格式
        dateSignFieldConfig.put("fontSize", 14);  // 日期字体大小
        dateSignFieldConfig.put("showSignDate","1");
        //日期显示位置信息
        List<Map<String, Object>> posisitonyDate = getKeywordPositions(fileId, "协议签订时间：");
        Map<String, Object> posisitonDa = null;
        if(posisitonyDate.size()>0){
            posisitonDa=posisitonyDate.get(0);
            dateSignFieldConfig.put("signDatePositionX", (Float)posisitonDa.get("positionX")+100f);   //签章区所在X坐标
            dateSignFieldConfig.put("signDatePositionY", posisitonDa.get("positionY"));   //签章区所在Y坐标
           // dateSignFieldConfig.put("signDatePositionPage", posisitonDa.get("pageNum"));   //签章区所在Y坐标
        }
        signFieldP.put("signDateConfig", dateSignFieldConfig);

        List<Map<String, Object>> signFieldsP = new ArrayList<>();
        signFieldsP.add(signFieldP);

        //附件的签署区配置
        Map<String, Object> signFieldP_F = new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
        signFieldP_F.put("fileId", fileId);    // 签署区所在待签署文件ID
        signFieldP_F.put("customBizNum", "");  // 开发者自定义业务编号

        signerP.put("signConfig", signConfigP);

        Map<String, Object> normalSignFieldConfigP_F = new HashMap<>(); //签章区配置项
        normalSignFieldConfigP_F.put("freeMode", false);  // 是否自由签章，默认值 false

        // 页面可选个人印章样式，默认值0和1（英文逗号分隔）0 - 手写签名 1 - 姓名印章 2 - 手写签名AI校验
        normalSignFieldConfigP_F.put("psnSealStyles", "0");

        normalSignFieldConfigP_F.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
        normalSignFieldConfigP_F.put("movableSignField", true);   //页面是否可移动签章区，默认值 false

        //农户签章的地方关键字
        List<Map<String, Object>> posisitony_F = getKeywordPositions(fileId, "承诺人（签字）：");
        Map<String, Object> posisitonP_F = null;
        Map<String, Object> signFieldPositionP_F = new HashMap<>(); // 签章区位置信息
        if (template.getPositionPage2()!=null){
            signFieldPositionP_F.put("positionX", template.getPositionAcross2());   //签章区所在X坐标
            signFieldPositionP_F.put("positionY", template.getPositionVertical2());   //签章区所在Y坐标
            signFieldPositionP_F.put("positionPage", template.getPositionPage2());
        }else {
            if(posisitony_F.size()>0){
                posisitonP_F=posisitony_F.get(0);
                signFieldPositionP_F.put("positionX", (Float)posisitonP_F.get("positionX")+110f);   //签章区所在X坐标
                signFieldPositionP_F.put("positionY", posisitonP_F.get("positionY"));   //签章区所在Y坐标
                signFieldPositionP_F.put("positionPage", posisitonP_F.get("pageNum"));
            }
        }

        normalSignFieldConfigP_F.put("signFieldPosition", signFieldPositionP_F);
        signFieldP_F.put("normalSignFieldConfig", normalSignFieldConfigP_F);

        Map<String, Object> signDateConfig_F = new HashMap<>(); //独立签署日期配置项
        signDateConfig_F.put("dateFormat", "yyyy年MM月dd日");  // 日期格式
        signDateConfig_F.put("fontSize", 14);  // 日期字体大小
        signDateConfig_F.put("showSignDate","1");
       /* //日期显示位置信息
        List<Map<String, Object>> posisitonyDate = getKeywordPositions(fileId, "甲方（签字捺印）:");

        if(posisitonyDate.size()>0){
            posisitonDa=posisitonyDate.get(0);
            dateSignFieldConfig.put("signDatePositionX", posisitonDa.get("positionX"));   //签章区所在X坐标
            dateSignFieldConfig.put("signDatePositionY", posisitonDa.get("positionY"));   //签章区所在Y坐标
        }*/
        if(posisitonP_F!=null){
            signDateConfig_F.put("signDatePositionX", (Float)posisitonP_F.get("positionX")+45f);   //签章区所在X坐标
            signDateConfig_F.put("signDatePositionY",  (Float)posisitonP_F.get("positionY")-25f);   //签章区所在Y坐标
        }
        signFieldP_F.put("signDateConfig", signDateConfig_F);
        signFieldsP.add(signFieldP_F);

        signerP.put("signFields", signFieldsP);

        signers.add(signerO);
        signers.add(signerP);

        //现在改成不管有没有共签人，共签人都不需要签--2024-11-05
        bpMobile="";
        //有共签人的共签人签署
        if(StringUtil.isNotBlank(bpMobile)){
            Map<String, Object> signerG = new HashMap<>();
            Map<String, Object> signConfigG = new HashMap<>();
            signConfigG.put("signOrder",3);
            signConfigG.put("signTaskType","0");
            signerG.put("signConfig", signConfigG);
            signerG.put("signerType",0);

            Map<String, Object> psnSignerInfoG = new HashMap<>();  //个人签署方信息
            psnSignerInfoG.put("psnAccount", bpMobile);   // 个人账号标识（手机号或邮箱）
            signerG.put("psnSignerInfo", psnSignerInfoG);

            Map<String, Object> signFieldG = new HashMap<>();  // 签署区信息（设置签署方 盖章/签名/文字输入的区域）
            signFieldG.put("fileId", fileId);    // 签署区所在待签署文件ID

            Map<String, Object> normalSignFieldConfigG = new HashMap<>(); //签章区配置项
            normalSignFieldConfigG.put("freeMode", false);  // 是否自由签章，默认值 false

            // 页面可选个人印章样式，默认值0和1（英文逗号分隔）0 - 手写签名 1 - 姓名印章 2 - 手写签名AI校验
            normalSignFieldConfigG.put("psnSealStyles", "0");

            normalSignFieldConfigG.put("signFieldStyle", "1");   // 签章区样式  1 - 单页签章，2 - 骑缝签章
            normalSignFieldConfigG.put("movableSignField", true);   //页面是否可移动签章区，默认值 false

            //农户签章的地方关键字
            List<Map<String, Object>> posisitonyG = getKeywordPositions(fileId, "共签人（如有）");
            Map<String, Object> posisitonG = null;
            Map<String, Object> signFieldPositionG = new HashMap<>(); // 签章区位置信息
            if(posisitonyG.size()>0){
                posisitonG=posisitonyG.get(0);
                signFieldPositionG.put("positionX", (Float)posisitonG.get("positionX")+200f);   //签章区所在X坐标
                signFieldPositionG.put("positionY", posisitonG.get("positionY"));   //签章区所在Y坐标
                signFieldPositionG.put("positionPage", posisitonG.get("pageNum"));
            }

            normalSignFieldConfigG.put("signFieldPosition", signFieldPositionG);
            signFieldG.put("normalSignFieldConfig", normalSignFieldConfigG);

            List<Map<String, Object>> signFieldsG = new ArrayList<>();
            signFieldsG.add(signFieldG);

            signerG.put("signFields", signFieldsG);

            signers.add(signerG);
        }



        Map<String, Object> param = new HashMap<>();
        param.put("docs", docs);
        param.put("signFlowConfig", signFlowConfig);
        param.put("signFlowInitiator", signFlowInitiator);
        param.put("signers", signers);
        Gson gson = new Gson();
        //请求参数body体,json格式。get或者delete请求时jsonString传空json:"{}"或者null
        String jsonParm = gson.toJson(param);
        logger.info(">>>>>>>>>>>>>>>>>>>>>>>createByFile jsonParam:{}", jsonParm);
        //请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        //生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId, eSignAppSecret, jsonParm, requestType.name(), apiaddr, true);
        //发起接口请求
        EsignHttpResponse createByFile = EsignHttpHelper.doCommHttp(eSignHost, apiaddr, requestType, jsonParm, header, true);
        JsonObject createByFileJsonObject = gson.fromJson(createByFile.getBody(), JsonObject.class);
        if (ESignConstants.SUCCESS.equals(createByFileJsonObject.get("code").toString())) {
            JsonObject createByFileData = createByFileJsonObject.getAsJsonObject("data");
            String signFlowId = createByFileData.get("signFlowId").getAsString();   // 签署流程ID
            logger.info(">>>>>>>>>>>>>>>>>>>>>>>>>>>createByFile  流程id:" + signFlowId);
            return signFlowId;
        } else {
            logger.error(">>>>>>>>>>>>>>>>>>>>>>>>>>>createTentConcatByFile " + createByFileJsonObject.get("message"));
            throw new EsignDemoException("发起签署失败!失败原因:" + createByFileJsonObject.get("message"));
        }
    }


    /**
     * 获取合同文件签署链接
     * @return  signFlowId 发起签署 返回的 签署流程id
     */
    public static Map<String,String> signUrl(String signFlowId,String mobile, String psnId) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/" + signFlowId + "/sign-url";
        Map<String,Object> params=new HashMap<>();
        params.put("signFlowId", signFlowId);
        params.put("needLogin", true);

        Map<String,Object> operator=new HashMap<>();
        if (StringUtil.isBlank(psnId)) {
            operator.put("psnAccount",mobile);  //签署人手机号
        } else {
                operator.put("psnId", psnId);
        }
        params.put("operator",operator);

        Map<String,Object> redirectConfig=new HashMap<>();
        redirectConfig.put("redirectUrl", EsignConfig.NotifyUrl+"/a/main/redirect/eSignSuccess");   //重定向地址
        params.put("redirectConfig", redirectConfig);

        Gson gson=new Gson();
        String jsonParm = gson.toJson(params);
        //请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        //生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId, eSignAppSecret, jsonParm, requestType.name(), apiaddr, true);
        //发起接口请求
        EsignHttpResponse signUrl=EsignHttpHelper.doCommHttp(eSignHost, apiaddr, requestType, jsonParm, header, true);
        JsonObject signUrlJsonObject = gson.fromJson(signUrl.getBody(), JsonObject.class);
        if(ESignConstants.SUCCESS.equals(signUrlJsonObject.get("code").getAsString())){
            JsonObject signUrlData = signUrlJsonObject.getAsJsonObject("data");
            String shortUrl = signUrlData.get("shortUrl").getAsString();
            String url = signUrlData.get("url").getAsString();
            logger.info(">>>>>>>>>>>>>signUrl 签署长链接:{},短链接：{}",url,shortUrl );
            Map<String,String> remap = Maps.newHashMap();
            remap.put("shortUrl",shortUrl);
            remap.put("url",url);
            return remap;
        }else{
            throw new EsignDemoException("获取签署失败!失败原因:"+signUrlJsonObject.get("message"));
        }
    }


    /**
     * 获取 下载已签署文件及附属材料(流程结束)
     *
     * @return signFlowId 发起签署 返回的 签署流程id
     */
    public static String fileDownloadUrl(String signFlowId) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/" + signFlowId + "/file-download-url";
        Map<String, Object> params = new HashMap<>();
        params.put("signFlowId", signFlowId);

        Gson gson = new Gson();
        String jsonParm = gson.toJson(params);
        //请求方法
        EsignRequestType requestType = EsignRequestType.GET;
        //生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId, eSignAppSecret, jsonParm, requestType.name(), apiaddr, true);
        //发起接口请求
        EsignHttpResponse signUrl = EsignHttpHelper.doCommHttp(eSignHost, apiaddr, requestType, jsonParm, header, true);
        JsonObject signUrlJsonObject = gson.fromJson(signUrl.getBody(), JsonObject.class);
        if (ESignConstants.SUCCESS.equals(signUrlJsonObject.get("code").toString())) {
            JsonArray componentsArray = signUrlJsonObject.getAsJsonObject("data").get("files").getAsJsonArray();
            String url = componentsArray.get(0).getAsJsonObject().get("downloadUrl").getAsString();
            return url;
        } else {
            throw new EsignDemoException("获取 下载已签署文件及附属材料链接失败!失败原因:" + signUrlJsonObject.get("message"));
        }
    }

    /**
     * 获取 下载下载签署中文件(流程未结束)
     *
     * @return signFlowId 发起签署 返回的 签署流程id
     */
    public static String filePreviewUrl(String signFlowId,String docFileId) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/" + signFlowId + "/preview-file-download-url?docFileId="+docFileId;
        Gson gson = new Gson();
        String jsonParm = "";
        //请求方法
        EsignRequestType requestType = EsignRequestType.GET;
        //生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId, eSignAppSecret, jsonParm, requestType.name(), apiaddr, true);
        //发起接口请求
        EsignHttpResponse signUrl = EsignHttpHelper.doCommHttp(eSignHost, apiaddr, requestType, jsonParm, header, true);
        JsonObject signUrlJsonObject = gson.fromJson(signUrl.getBody(), JsonObject.class);
        if (signUrlJsonObject.get("code").getAsInt()==0) {
            JsonObject dataObject = signUrlJsonObject.getAsJsonObject("data");
            String url = dataObject.get("fileDownloadUrl").getAsString();
            return url;
        } else {
            throw new EsignDemoException("获取 下载下载签署中文件!失败原因:" + signUrlJsonObject.get("message"));
        }
    }

    /**
     * 撤销合同文件签署
     *
     * @return signFlowId 发起签署 返回的 签署流程id
     */
    public static void revoke(String signFlowId) throws EsignDemoException {
        String apiaddr = "/v3/sign-flow/" + signFlowId + "/revoke";
        Map<String, Object> params = new HashMap<>();
        params.put("signFlowId", signFlowId);
        // 撤销原因 【注】撤销原因最多50字
        params.put("revokeReason", "EPC公司主动撤销");

        Gson gson = new Gson();
        String jsonParm = gson.toJson(params);
        //请求方法
        EsignRequestType requestType = EsignRequestType.POST;
        //生成请求签名鉴权方式的Header
        Map<String, String> header = EsignHttpHelper.signAndBuildSignAndJsonHeader(eSignAppId, eSignAppSecret, jsonParm, requestType.name(), apiaddr, true);
        //发起接口请求
        EsignHttpResponse signUrl = EsignHttpHelper.doCommHttp(eSignHost, apiaddr, requestType, jsonParm, header, true);
        JsonObject signUrlJsonObject = gson.fromJson(signUrl.getBody(), JsonObject.class);
        logger.info(">>>>>>>>>>>>>revoke 撤销合同流程id:{},返回消息：{}", signFlowId, signUrlJsonObject.get("message").toString());
    }

    public static  void main(String[] arr) throws EsignDemoException {
       /* getKeywordPositions("3f7d97e953374237b16ec38f262c93c7","乙方(盖章)");*/
        String uarl=filePreviewUrl("4a7a41d4cb1c43fa989a365cd1dfc926","dffc71e097bc41699476201ce866b341");
       System.out.println(uarl);
    }

}
