package com.dgtly.wxportal.service.impl;


import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.dgtly.common.config.Global;
import com.dgtly.common.constant.Constants;
import com.dgtly.common.utils.DateUtils;
import com.dgtly.common.utils.http.HttpUtils;
import com.dgtly.system.domain.*;

import com.dgtly.system.service.ITransferLogService;
import com.dgtly.wxportal.config.ESignConfig;
import com.dgtly.wxportal.domain.OrderFile;
import com.dgtly.wxportal.service.IEsignSignService;
import com.dgtly.wxportal.service.IOrderFileService;
import com.dgtly.wxportal.utils.ESign.ESignHttpUtil;
import com.dgtly.wxportal.utils.ESign.ESignUrl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;


import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * @description:签署服务API
 * @author:qxm
 * @date:2020/10/13 10:31
 */
@Slf4j
@Service
public class EsignSignServiceImpl implements IEsignSignService {

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

    @Autowired
    private ESignHttpUtil eSignHttpUtil;
    @Autowired
    private ESignConfig eSignConfig;
    @Autowired
    private IOrderFileService orderFileService;
    @Autowired
    private RestTemplate restTemplate;
    @Value(value = "${ruoyi.cloudPath}")
    private String cloudPath;
    //完成收货回调
    private String confirmUrl="order/order/deliver-quantity-confirm/confirmCollect";
    //E签宝签署完需返回给tms
    @Value(value = "${spring.tms.tmsToken}")
    private String tmsToken;
    @Value(value = "${spring.tms.tmsUrl}")
    private String tmsUrl;
    @Value(value = "${spring.tms.suishenbang}")
    private String suishenbang;



    @Autowired
    private ITransferLogService transferLogService;

    /**
     * @description: 授权
     * @param: [businessScene, fileId, posX, posY, fileName, signerAccountId, authorizedAccountId, redirectUrl]
     * @return: java.lang.String
     * @author: njs
     * @date: 2023/3/23 14:06
     */
    @Override
    public String oneStepFlowempowerByAuth(String businessScene, String fileId, float posX, float posY, String fileName, String signerAccountId, String authorizedAccountId, String redirectUrl) {
        JSONObject json = buildParam(businessScene, fileId,posX,posY,fileName, signerAccountId,authorizedAccountId,redirectUrl);
        JSONObject jsonObject = eSignHttpUtil.doPostGetJson(ESignUrl.CreateFlowOneStepUrl,json);
        JSONObject result = (JSONObject)jsonObject.get("data");
        return result.get("flowId").toString();
    }

    /**
     * @description: 司机授权书
     * @param: [businessScene, fileId, posX, posY, posX2, posY2, fileName, signerAccountId, authorizedAccountId, redirectUrl]
     * @return: java.lang.String
     * @author: njs
     * @date: 2023/2/28 16:10
     */
    @Override
    public String oneStepFlowDriver(String businessScene, String fileId, float posX, float posY, float posX2, float posY2, String fileName, String signerAccountId, String authorizedAccountId, String redirectUrl) {
        JSONObject json = buildParamDriver(businessScene, fileId,posX,posY,posX2,posY2, fileName, signerAccountId,authorizedAccountId,redirectUrl);
        JSONObject jsonObject = eSignHttpUtil.doPostGetJson(ESignUrl.CreateFlowOneStepUrl,json);
        JSONObject result = (JSONObject)jsonObject.get("data");
        return result.get("flowId").toString();
    }
    /**
     * @param businessScene
     * @param fileId
     * @param posX
     * @param posY
     * @param fileName
     * @param signerAccountId
     * @param authorizedAccountId
     * @param redirectUrl
     * @description: 一步发起签署
     * @param: [accountId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/12 16:05
     */
    @Override
    public String oneStepFlow(String businessScene, String fileId, float posX, float posY, String fileName, String signerAccountId, String authorizedAccountId, String redirectUrl) {
        JSONObject json = buildParam(businessScene, fileId,posX,posY, fileName, signerAccountId,authorizedAccountId,redirectUrl);
        JSONObject jsonObject = eSignHttpUtil.doPostGetJson(ESignUrl.CreateFlowOneStepUrl,json);
        JSONObject result = (JSONObject)jsonObject.get("data");
        return result.get("flowId").toString();
    }

    /**
     * @description: 开启签署流程
     * @param: [flowId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/12 16:05
     */
    @Override
    public String processStart(String flowId) {
        JSONObject json = new JSONObject();
//        json.put("flowId", flowId);
        JSONObject jsonObject = eSignHttpUtil.doPutGetJson(ESignUrl.ProcessStartUrl, json,flowId);
        return jsonObject.toJSONString();
    }

    /**
     * @description: 设置静默签署
     * @param: [accountId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/29 17:18
     */
    @Override
    public String signAuth(String accountId) {
        JSONObject json = new JSONObject();
//        json.put("flowId", flowId);
        JSONObject jsonObject = eSignHttpUtil.doPostGetJson(ESignUrl.signAuthUrl, json,accountId);
        return jsonObject.toJSONString();
    }

    /**
     * @description: 查询签署人列表
     * @param: [flowId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/12 16:05
     */
    @Override
    public String processExecuteSigners(String flowId) {
        JSONObject json = new JSONObject();
//        json.put("flowId", flowId);
        JSONObject jsonObject = eSignHttpUtil.doGetGetJson(ESignUrl.ProcessExecuteSignersUrl, json,flowId);
        return jsonObject.toJSONString();
    }

    /**
     * @description: 获取签署地址
     * @param: [flowId，accountId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/12 16:05
     */
    @Override
    public String processExecuteUrl(String flowId,String accountId,String organizeId) {
        JSONObject json = new JSONObject();
//        json.put("flowId", flowId);
        JSONObject jsonObject = eSignHttpUtil.doGetGetJson(ESignUrl.ProcessExecuteUrl, json,flowId,accountId,organizeId);
        return jsonObject.toJSONString();
    }

    /**
     * @description: 流程归档
     * @param: [flowId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/12 16:05
     */
    @Override
    public String processArchiv(String flowId) {
        JSONObject json = new JSONObject();
//        json.put("flowId", flowId);
        JSONObject jsonObject = eSignHttpUtil.doPutGetJson(ESignUrl.ProcessArchivUrl, json,flowId);
        return jsonObject.toJSONString();
    }

    /**
     * @description: 流程文件下载
     * @param: [flowId]
     * @return: java.lang.String
     * @author: qxm
     * @date: 2020/10/12 16:05
     */
    @Override
    public String processDocumentDownload(String flowId) {
        JSONObject json = new JSONObject();
//        json.put("flowId", flowId);
        JSONObject jsonObject = eSignHttpUtil.doGetGetJson(ESignUrl.ProcessDocumentDownloadUrl, json,flowId);
        JSONObject result1 = (JSONObject)jsonObject.get("data");
        JSONArray jsonarray = (JSONArray)result1.get("docs");
        JSONObject result = (JSONObject)jsonarray.get(0);
        return result.get("fileUrl").toString();
    }

    @Override
    @Async
    public void callbackNotice(OrderFile orderFlag) {
        try {
            String param;
            if (orderFlag.getWareHouseCode()!=null&&orderFlag.getWareHouseName()!=null){
                param = "?shipmentNumber="+orderFlag.getShipmentNumber()+"&belongTo="+orderFlag.getChainsCode()+"&confirmBy="+orderFlag.getSignerName()+"&wareHouseCode="+orderFlag.getWareHouseCode()+"&wareHouseName="+orderFlag.getWareHouseName();
//                param = "shipmentNumber="+orderFlag.getShipmentNumber()+"&belongTo="+orderFlag.getChainsCode()+"&wareHouseCode="+orderFlag.getWareHouseCode()+"&wareHouseName="+orderFlag.getWareHouseName();
            }else{
                param = "?shipmentNumber="+orderFlag.getShipmentNumber()+"&belongTo="+orderFlag.getChainsCode()+"&confirmBy="+orderFlag.getSignerName();
//                param = "shipmentNumber="+orderFlag.getShipmentNumber()+"&belongTo="+orderFlag.getChainsCode();
            }
//            String url =cloudPath+confirmUrl;
            String url =cloudPath+confirmUrl+param;
            String str = restTemplate.getForObject(url, String.class);
            log.info("result res : "+str);
            JSONObject result = JSONObject.parseObject(str);
//        JSONObject result = (JSONObject) JSONObject.parse(HttpUtils.sendGet(url,param));

            /*保存回调消息*/
            OrderFile orderFile = new OrderFile();
            orderFile.setFlowId(orderFlag.getFlowId());
            orderFile.setCode(result.get("code").toString());
            orderFile.setMessage(result.get("message").toString());
            orderFileService.updateOrderFileByFlowId(orderFile);
        } catch (RestClientException e) {
            e.printStackTrace();
            logger.error("修改订单回调错误",e);
            throw e;
        }
    }

    @Override
    @Async
    public void saveFile(String flowId, OrderFile orderFlag) throws IOException {
//        System.out.println("executeAysncTask1 method: 执行异步保存{} -------"+ i);
        String fileUrl = processDocumentDownload(flowId);
        String uId=UUID.randomUUID().toString();
        /*下载保存签署后的文件，返回文件存储地址*/
        OrderFile orderFile = new OrderFile();
        orderFile.setFlowId(flowId);
        if(orderFlag.getTypes().equals(1)){
            downloadFile(Global.getPdfPath(), orderFlag.getFlowId()+uId + ".pdf", fileUrl);
            orderFile.setFileUrl(Constants.RESOURCE_PREFIX+"/pdf/"+DateUtils.datePath()+"/"+orderFlag.getFlowId()+uId + ".pdf");
            log.info("E签宝 = [{}], 流程id = [{}]",orderFile.getFileUrl(),orderFile.getFlowId());
            orderFileService.updateOrderFileByFlowId(orderFile);
            tmsCertificate(orderFlag.getDeliveryNumber(),Constants.RESOURCE_PREFIX+"/pdf/"+DateUtils.datePath()+"/"+orderFlag.getFlowId()+uId + ".pdf");
        }else if( orderFlag.getTypes().equals(2)){
            downloadFile(Global.getPdfPath(), orderFlag.getFlowId()+uId + "_签收订单.pdf", fileUrl);
            orderFile.setFileUrl(Constants.RESOURCE_PREFIX+"/pdf/"+DateUtils.datePath()+"/"+orderFlag.getFlowId()+uId + "_签收订单.pdf");
            log.info("E签宝 = [{}], 流程id = [{}]",orderFile.getFileUrl(),orderFile.getFlowId());
            orderFileService.updateOrderFileByFlowId(orderFile);
        }else{
            downloadFile(Global.getPdfPath(), orderFlag.getFlowId()+uId + "_授权委托.pdf", fileUrl);
            orderFile.setFileUrl(Constants.RESOURCE_PREFIX+"/pdf/"+DateUtils.datePath()+"/"+orderFlag.getFlowId()+uId + "_授权委托.pdf");
            log.info("E签宝 = [{}], 流程id = [{}]",orderFile.getFileUrl(),orderFile.getFlowId());
            orderFileService.updateOrderFileByFlowId(orderFile);
        }
    }
    /**
     * @description: orders交货单
     * @param: [orders, certificateUrl]
     * @return: void
     * @author: njs
     * @date: 2023/4/12 18:29
     */
    @Override
    public void tmsCertificate(String orders,String certificateUrl) throws IOException {
        //        获取请求参数
        String url = tmsUrl;
        String token = tmsToken;
        long ts = System.currentTimeMillis();
        String sign = new Digester(DigestAlgorithm.MD5).digestHex(new Digester(DigestAlgorithm.SHA1).digestHex(StringUtils.join(token, ts)));
//        发送请求
        // name1=value1&name2=value2
        String pj = "orders="+orders+"&authFile="+suishenbang+certificateUrl;
        String jsonObject= HttpUtils.sendTmsPost(url,pj,ts,sign);
        JSONObject object=JSONObject.parseObject(jsonObject);
        log.info("Tms url = [{}], params = [{}], token = [{}]", url, pj, token);
//        解析返回值
        String code = object.getString("sys_code");
        TransferLog transferLog = new TransferLog();
        transferLog.setAuthFile(certificateUrl);
        transferLog.setCodeing(code);
        transferLog.setDeliveryNumber(orders);
        transferLog.setRemarks("向TMS发送签署司机授权书");
        transferLogService.insertTransferLog(transferLog);



    }


    /**
     * @description 模拟构建一步发起请求参数
     *              <p>
     *              这里模拟的场景是：无附件，一个抄送人，一个文件，一个平台方和一个待签署方
     *              <p>
     *              实际使用时，可以根据贵司的业务场景，选择填入附件信息、抄送人列表、文件列表、签署方信息
     *              <p>
     *              注意： 请求参数中的signers中的签署文件fileId，必须在待签文档信息docs中有填写，否则报错
     *
     *              <p>
     *
     */
    private  JSONObject buildParam(String businessScene, String fileId,float posX,float posY, String fileName, String signerAccountId,String authorizedAccountId,String redirectUrl) {
        // 附件信息列表 这里模拟没有附件的情况
        List<Attachment> attachments = new ArrayList<>();

        // 抄送人列表 这里模拟有一个抄送人
        Copier copier = new Copier(signerAccountId, 0, null);
        List<Copier> copiers = new ArrayList<>(); // Lists.newArrayList() 是guava 的写法
        copiers.add(copier);

        // 待签文件列表，这里模拟只有一个待签文件
        Doc doc = new Doc(fileId, fileName);

        List<Doc> docs = new ArrayList<>();//Lists.newArrayList(doc);
        docs.add(doc);

        // 流程配置，可以不配置，使用默认配置
        String noticeDeveloperUrl = eSignConfig.getSignSuccessUrl();//回调通知URL
        FlowConfigInfo flowConfigInfo = new FlowConfigInfo(noticeDeveloperUrl, "1,2", null, null);
        FlowInfo flowInfo = new FlowInfo(true,true,businessScene,flowConfigInfo);

        // 签署方信息
        // 平台方
        PosBeanInfo posBean1 = new PosBeanInfo("1", posX, posY); // 签署位置
        SignfieldInfo signfield1 = new SignfieldInfo(true, fileId, null, null, null, posBean1, null); // 签署区（签署主体是公司）

//        SignfieldInfo signfield1 = new SignfieldInfo(false, fileId, null, null, null, posBean1, null); // 签署区（个人签署）
        List<SignfieldInfo> signfields = new ArrayList<>();
        signfields.add(signfield1);
//        SignerAccount signAccount = new SignerAccount(signerAccountId, signerAccountId);//签署方账号
        SignerAccount signAccount = new SignerAccount(authorizedAccountId);//签署方账号
        Signer signer1 = new Signer(false, 1, signAccount, signfields, null); // 签署方
        // 用户方
//        PosBeanInfo posBean2 = new PosBeanInfo("1", 200F, 100F); // 签署位置
//        SignfieldInfo signfield2 = new SignfieldInfo(false, null, fileId, null, null, null, posBean2, null); // 签署区
//        List<SignfieldInfo> signfields1 = new ArrayList<>();
//        signfields1.add(signfield2);
//        Signer signer2 = new Signer(false, 1, signAccount, signfields1, null); //用户方
        List<Signer> signers = new ArrayList<>();//Lists.newArrayList(signer1, signer2);
        signers.add(signer1);
//        signers.add(signer2);

        //拼接参数
        return buildOneStepFlowParam(attachments, copiers, docs, flowInfo, signers);
    }

    private  JSONObject buildParamDriver(String businessScene, String fileId,float posX,float posY,float posX2,float posY2, String fileName, String signerAccountId,String authorizedAccountId,String redirectUrl) {
        // 附件信息列表 这里模拟没有附件的情况
        List<Attachment> attachments = new ArrayList<>();

        // 抄送人列表 这里模拟有一个抄送人
        Copier copier = new Copier(signerAccountId, 0, null);
        List<Copier> copiers = new ArrayList<>(); // Lists.newArrayList() 是guava 的写法
        copiers.add(copier);

        // 待签文件列表，这里模拟只有一个待签文件
        Doc doc = new Doc(fileId, fileName);

        List<Doc> docs = new ArrayList<>();//Lists.newArrayList(doc);
        docs.add(doc);

        // 流程配置，可以不配置，使用默认配置
        String noticeDeveloperUrl = eSignConfig.getSignSuccessUrl();//回调通知URL
        FlowConfigInfo flowConfigInfo = new FlowConfigInfo(noticeDeveloperUrl, "1,2", null, null);
        FlowInfo flowInfo = new FlowInfo(true,true,businessScene,flowConfigInfo);

        // 签署方信息
        // 平台方
        PosBeanInfo posBean1 = new PosBeanInfo("1", posX, posY); // 签署位置
        PosBeanInfo posBean2 = new PosBeanInfo("1", posX2, posY2); // 签署位置
        SignfieldInfo signfield1 = new SignfieldInfo(true, fileId, null, null, null, posBean1, null); // 签署区（签署主体是公司）
        SignfieldInfo signfield2 = new SignfieldInfo(true, fileId, null, null, null, posBean2, null); // 签署区（签署主体是公司）

//        SignfieldInfo signfield1 = new SignfieldInfo(false, fileId, null, null, null, posBean1, null); // 签署区（个人签署）
        List<SignfieldInfo> signfields = new ArrayList<>();
        signfields.add(signfield1);
        signfields.add(signfield2);
//        SignerAccount signAccount = new SignerAccount(signerAccountId, signerAccountId);//签署方账号
        SignerAccount signAccount = new SignerAccount(authorizedAccountId);//签署方账号
        Signer signer1 = new Signer(false, 1, signAccount, signfields, null); // 签署方
        // 用户方
//        PosBeanInfo posBean2 = new PosBeanInfo("1", 200F, 100F); // 签署位置
//        SignfieldInfo signfield2 = new SignfieldInfo(false, null, fileId, null, null, null, posBean2, null); // 签署区
//        List<SignfieldInfo> signfields1 = new ArrayList<>();
//        signfields1.add(signfield2);
//        Signer signer2 = new Signer(false, 1, signAccount, signfields1, null); //用户方
        List<Signer> signers = new ArrayList<>();//Lists.newArrayList(signer1, signer2);
        signers.add(signer1);
//        signers.add(signer2);

        //拼接参数
        return buildOneStepFlowParam(attachments, copiers, docs, flowInfo, signers);
    }

    /**
     * @description 一步发起签署 -- 构建请求参数
     *              <p>
     *
     *              attachments:附件信息列表【可空】
     *              <p>
     *              copiers：抄送人列表【可空】
     *              <p>
     *              docs:待签文档信息【可空】
     *              <p>
     *              flowInfo:流程基本信息【可空】
     *              <p>
     *              signers:签署方信息列表【必填】
     *
     */
    public static JSONObject buildOneStepFlowParam(List<Attachment> attachments, List<Copier> copiers, List<Doc> docs,
                                                   FlowInfo flowInfo, List<Signer> signers) {
        JSONObject json = new JSONObject();
//        json.put("attachments", attachments);
//        json.put("copiers", copiers);
        json.put("docs", docs);
        json.put("flowInfo", flowInfo);
        json.put("signers", signers);
        return json;
    }

    /**
     * @description: 下载文件
     * @param: [filePath, fileName, httpUrl]
     * @return: void
     * @author: qxm
     * @date: 2020/10/27 9:58
     */
    public static void downloadFile(String filePath,String fileName,String httpUrl){
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;
        FileInputStream inputStream=null;
        try {
            URL url = new URL(httpUrl);
            HttpURLConnection connection =  (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.connect();
            InputStream is = connection.getInputStream();

            bis = new BufferedInputStream(is);
            File file = new File(filePath+"/"+ DateUtils.datePath()+"/"+fileName);//E:\test.pdf
            if (!file.getParentFile().exists())
            {
                file.getParentFile().mkdirs();
            }
            FileOutputStream fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            int b = 0;
            byte[] byArr = new byte[1024*4];
            while((b=bis.read(byArr))!=-1){
                bos.write(byArr, 0, b);
            }

//            inputStream = new FileInputStream(file);
//            MultipartFile multipartFile = new MockMultipartFile("file", file.getName(), "text/plain", IOUtils.toByteArray(inputStream));
//            FileUploadUtils.extractFilename(multipartFile);
//            String uploadPath = FileUploadUtils.upload(Global.getPdfPath(), multipartFile);
//            return uploadPath;

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(bis!=null){
                    bis.close();
                }
                if(bos!=null){
                    bos.close();
                }
                if(inputStream!=null){
                    inputStream.close();
                }
//                File file1 = new File(filePath+"/"+fileName);
//                if (!file1.isDirectory()) {
//                    file1.delete();
//                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

}
