package com.bcxin.signature.components;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.backend.core.components.JsonProvider;
import com.bcxin.backend.core.edis.EDIConstants;
import com.bcxin.backend.core.edis.JTLZResponseValueEDI;
import com.bcxin.backend.core.exceptions.SaasRetryableException;
import com.bcxin.backend.core.utils.RetryUtil;
import com.bcxin.signature.config.FileModeConfig;
import com.bcxin.signature.config.FileWriteConfig;
import com.bcxin.signature.util.ftp.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Component
public class JTLZPushComponent {
    private static final Logger logger = LoggerFactory.getLogger(JTLZPushComponent.class);
    private static AtomicInteger IncrementStep = new AtomicInteger(0);
    private final JTLZComponent jtlzComponent;
    private final JsonProvider jsonProvider;

    public JTLZPushComponent(JTLZComponent jtlzComponent, JsonProvider jsonProvider) {
        this.jtlzComponent = jtlzComponent;
        this.jsonProvider = jsonProvider;
    }

    public void execute(String traceId, String readFtpName) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        FtpConnection ftp = ThreadFtpContext.getFtpConnection();
        String[] list = null;
        Exception metaException = null;
        Exception subException = null;
        Collection<JTLZResponseValueEDI> jtlzEdis = new HashSet<>();
        String fileContent = null;
        try {
            //读取文件
           try {
               fileContent = FtpUtil.getFileContent(ftp, FileModeConfig.getFilePath(), readFtpName);
           }
           catch (Exception ex) {
               logger.error("RETRY-Failed to obtain ftp content :{}", readFtpName, ex);
               fileContent = FtpUtil.getFileContent(FileModeConfig.getFilePath(), readFtpName);
           }

            if (StringUtils.isEmpty(fileContent)) {
                return;
            }

            try {
                list = fileContent.split(",");
                for (String filename : list) {
                    if (!org.springframework.util.StringUtils.hasLength(filename)) {
                        logger.error("unexpected filename={}", filename);
                        continue;
                    }

                    JTLZResponseValueEDI ediValue = null;
                    StopWatch subStopWatch = new StopWatch();
                    subStopWatch.start();
                    Exception lastException = null;
                    try {
                        String content = FtpUtil.getFileContent(FileModeConfig.getFilePath(), filename);
                        /**
                         * 直接忽略找不到文件的情况, 针对这些文件,系统会另外处理
                         */
                        if(!StringUtils.isEmpty(content)) {
                            ediValue = jtlzServer(filename, content,false);
                            logger.error("success with {}->", filename, ediValue.getFileName());
                        }
                    } catch (Exception e) {
                        lastException = e;
                    } finally {
                        if(ediValue!=null) {
                            jtlzEdis.add(ediValue);
                        }
                        subStopWatch.stop();
                        logger.error("{}-{} ====>filename: {} cost {} seconds jtlzTask.signatureJTLZ.jtlzServer,{}",
                                traceId,
                                readFtpName,
                                filename, subStopWatch.getTotalTimeSeconds(),
                                (lastException == null ? "success" : "failed"),
                                lastException);
                    }
                }
            } catch (Exception ex) {
                subException = ex;
            }
        } catch (Exception ex) {
            metaException = ex;
            logger.error("metaException-ERROR {}",readFtpName,ex);
        } finally {
            stopWatch.stop();
            logger.error("{}-({}) Done for signatureJTLZ cost {} seconds {}.list.size=({}) jtlzTask.signatureJTLZ.noFile({},{}).readFtpName：{}; ",
                    traceId,
                    (subException == null ? "SUCCESS" : "ERROR"),
                    stopWatch.getTotalTimeSeconds(),
                    readFtpName,
                    (list == null ? 0 : list.length),
                    FileModeConfig.getUserName(), FileModeConfig.getFilePath(), readFtpName,
                    subException);

            if(!CollectionUtils.isEmpty(jtlzEdis)) {
                Exception lastException = null;
                StringBuilder trace = new StringBuilder();
                try {
                    String batchContent = JSONObject.toJSONString(jtlzEdis);
                    String fileName =
                            String.format("%s-%s_%s%s",
                                    EDIConstants.PUSH_BATCH_CALLBACK_OUT_FILE_PREFIX,
                                    IncrementStep.incrementAndGet(),
                                    readFtpName.replace(EDIConstants.PUSH_FILE_EXTENSION, ""),
                                    EDIConstants.PUSH_FILE_EXTENSION
                            );

                    trace.append(String.format("filename=%s;", fileName));
                    boolean rt = FtpWriteUtil.uploadBase64(FileWriteConfig.getFilePath(), fileName, batchContent);
                    trace.append(String.format("rt=%s", rt));
                } catch (Exception ex) {
                    lastException = ex;
                } finally {
                    logger.error("{}-Done-IMPORTANT for batch file(jtlzEdis={},track={}, fileName={})",
                            (lastException == null ? "SUCCESS" : "ERROR"),
                            jtlzEdis.size(),
                            trace,
                            readFtpName,
                            lastException);
                }
            }

            /**
             * 不管怎样都先删除
             */
            if (metaException == null || true) {
                StringBuilder sb = new StringBuilder();
                try {
                    sb.append("begin to delete filename=" + readFtpName);
                    try{
                        ftp.delectFile(FileModeConfig.getFilePath(), readFtpName);
                    }
                    catch (Exception ee) {
                        Exception tryException = null;
                        try {
                            FtpUtil.delFilename(FileModeConfig.getFilePath(), readFtpName);
                        } catch (Exception e2) {
                            tryException = e2;
                        } finally {
                            logger.error("({})RETRY-Failed to delete ftp",
                                    (tryException == null ? "SUCCESS" : "ERROR"),
                                    readFtpName);
                        }
                    }
                    sb.append("step2;");

                    logger.error("readFtpName-success:{}",readFtpName,metaException);
                } catch (Exception ex) {
                    logger.error("readFtpName-failed to delete filename={};step={};exception={}", readFtpName, sb, ex.getMessage());
                }

            } else {
                logger.error("read meta file(path={}, fileName={}) content exception", FileModeConfig.getFilePath(), readFtpName, metaException);
            }

            try {
                try {
                    ftp.disconnect();
                } catch (Exception ex) {
                }

                ThreadFtpContext.disConnectFtpWriter();
            } catch (Exception ex) {
                logger.error("ThreadFtpContext disconnect", ex);
            }
        }
    }

    /**
     * 执行亮证功能
     * @param traceId
     * @param list
     */
    public void execute(String traceId, String[] list,boolean isFz) {
        Collection<JTLZResponseValueEDI> jtlzEdis = new HashSet<>();
        Exception subException = null;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        try {
            for (String filename : list) {
                if (!org.springframework.util.StringUtils.hasLength(filename)) {
                    logger.error("directly-execute unexpected filename={}", filename);
                    continue;
                }

                JTLZResponseValueEDI ediValue = null;
                StopWatch subStopWatch = new StopWatch();
                subStopWatch.start();
                Exception lastException = null;
                try {
                    String content = FtpUtil.getFileContent(FileModeConfig.getFilePath(), filename);
                    if (StringUtils.isEmpty(content)) {
                        ediValue = jtlzNullRet(filename,true);
                    } else {
                        if (isFz) {
                            /**
                             * 针对废止的数据; 直接产生OUT文件即可
                             */
                            jtlzFzServer(filename, content);
                        } else {
                            ediValue = jtlzServer(filename, content, true);
                        }
                    }
                    logger.error("directly-execute success with {}->", filename, ediValue.getFileName());
                } catch (Exception e) {
                    lastException = e;
                    ediValue = jtlzErrRet(filename, e.getMessage(),true);
                } finally {
                    if (ediValue != null) {
                        jtlzEdis.add(ediValue);
                    }
                    subStopWatch.stop();
                    logger.error("{}-{} ====>directly-execute: {} cost {} seconds jtlzTask.signatureJTLZ.jtlzServer,{}",
                            traceId,
                            (list == null ? "EMPTY" : list.length),
                            filename, subStopWatch.getTotalTimeSeconds(),
                            (lastException == null ? "success" : "failed"),
                            lastException);
                }
            }
        } catch (Exception ex) {
            subException = ex;
        } finally {
            stopWatch.stop();
            logger.error("{}-Done for directly-execute process files cost {} seconds size=({})",
                    (subException == null ? "SUCCESS" : "ERROR"),
                    stopWatch.getTotalTimeSeconds(),
                    (list == null ? "EMPTY" : list.length), subException);


            if (!CollectionUtils.isEmpty(jtlzEdis)) {
                Exception lastException = null;
                StringBuilder trace = new StringBuilder();
                String readFtpName = String.format("directly-%s", DateUtil.format(DateUtil.date(), "yyyyMMddHHmm"));
                try {
                    String batchContent = JSONObject.toJSONString(jtlzEdis);
                    String fileName =
                            String.format("%s-%s_%s%s",
                                    EDIConstants.PUSH_BATCH_CALLBACK_OUT_FILE_PREFIX,
                                    IncrementStep.incrementAndGet(),
                                    readFtpName,
                                    EDIConstants.PUSH_FILE_EXTENSION
                            );

                    trace.append(String.format("filename=%s;", fileName));
                    boolean rt = FtpWriteUtil.uploadBase64(FileWriteConfig.getFilePath(), fileName, batchContent);
                    trace.append(String.format("rt=%s", rt));
                } catch (Exception ex) {
                    lastException = ex;
                } finally {
                    logger.error("{}-Done-IMPORTANT for batch file(jtlzEdis={},track={}, fileName={})-{}",
                            (lastException == null ? "SUCCESS" : "ERROR"), jtlzEdis.size(), trace, readFtpName,
                            lastException);
                }
            }
        }
    }

    private JTLZResponseValueEDI jtlzNullRet(String filename,boolean outputFile) {
        if(StringUtils.isEmpty(filename)) {
            return null;
        }

        String outFilename = filename.replace("IN-", "OUT-");
        String result = "{\"ack_code\":\"FAILURE\",\"errors\":[{\"code\":\"12409\",\"severity\":\"ERROR\",\"message\":\"文件不存在或内容为空或异常\",\"innerCode\":\"\"}],\"sign\":null,\"sign_method\":null,\"timestamp\":null,\"correlation_id\":null,\"response_id\":\"a40e028c-d566-44fc-a2fa-ee4b8df715dc\",\"data\":null}";
        //新内容写入前缀为OUT|的文件
        boolean rt = false;
        if(outputFile || true) {
            rt = FtpWriteUtil.uploadBase64(FileWriteConfig.getFilePath(), outFilename, result);
        }

        return JTLZResponseValueEDI.create(
                outFilename,
                result,
                rt
        );
    }

    private JTLZResponseValueEDI jtlzErrRet(String filename,String msg,boolean outputFile) {
        if(StringUtils.isEmpty(filename)) {
            return null;
        }

        String outFilename = filename.replace("IN-", "OUT-");
        String result = "{\"ack_code\":\"FAILURE\",\"errors\":[{\"code\":\"12409\",\"severity\":\"ERROR\",\"message\":\"" + msg + "\",\"innerCode\":\"\"}],\"sign\":null,\"sign_method\":null,\"timestamp\":null,\"correlation_id\":null,\"response_id\":\"a40e028c-d566-44fc-a2fa-ee4b8df715dc\",\"data\":null}";
        //新内容写入前缀为OUT|的文件
        boolean rt = false;
        if(outputFile || true) {
            rt = FtpWriteUtil.uploadBase64(FileWriteConfig.getFilePath(), outFilename, result);
        }

        return JTLZResponseValueEDI.create(
                outFilename,
                result,
                rt
        );
    }

    protected JTLZResponseValueEDI jtlzServer(String filename, String content,boolean outputFile) {
        if (StringUtils.isEmpty(filename)) {
            return null;
        }
        String outFilename = filename.replace("IN-", "OUT-");
        String[] arr = filename.split("-");

        String item_code = arr[3];
        String result = this.jtlzComponent.license_issue(item_code, content);
        if (!StringUtils.isEmpty(result) && result.contains(EDIConstants.MESSAGE_DUPLICATE_CERTIFICATE_DOCUMENT)) {
            StringBuilder trace = new StringBuilder();
            Exception lastException = null;
            try {
                trace.append("step0;");
                Map map = this.jsonProvider.getData(content, Map.class);
                trace.append(String.format("step1;=%s;", map == null));
                JSONObject dataObject = (JSONObject) map.get("data");
                trace.append(String.format("step2;=%s;", dataObject == null));
                /**
                 * 废止的Map
                 */
                JSONObject feizhiMap = new JSONObject();
                feizhiMap.put(EDIConstants.PARAM_API_LIANG_ZHENG_SERVICE_ITEM_CODE, dataObject.get(EDIConstants.PARAM_API_LIANG_ZHENG_SERVICE_ITEM_CODE));
                feizhiMap.put(EDIConstants.PARAM_API_LIANG_ZHENG_SERVICE_ITEM_NAME, dataObject.get(EDIConstants.PARAM_API_LIANG_ZHENG_SERVICE_ITEM_NAME));
                feizhiMap.put(EDIConstants.PARAM_API_LIANG_ZHENG_BIZ_NUM, UUID.randomUUID().toString());
                trace.append(String.format("step3;=%s;", dataObject == null));
                JSONObject data_fields = dataObject.getJSONObject("data_fields");
                trace.append(String.format("step4;=%s;", data_fields == null));
                /**
                 * 这个是证件信息
                 */
                String ZZHM = data_fields.getString("ZZHM");
                trace.append(String.format("step5;=%s;", ZZHM == null));
                feizhiMap.put(EDIConstants.PARAM_API_LIANG_ZHENG_ID_CODE, ZZHM);
                feizhiMap.put(EDIConstants.PARAM_API_LIANG_ZHENG_OPERATOR, dataObject.get(EDIConstants.PARAM_API_LIANG_ZHENG_OPERATOR));
                trace.append("step6;");
                JSONObject data = new JSONObject();
                data.put("data", feizhiMap);
                String body = data.toJSONString();
                /**
                 * 怀疑是这个影响
                 */
                if (true) {
                    result = this.jtlzComponent.license_issue_fz(item_code, body);
                }

                trace.append("step7;");
            } catch (Exception ex) {
                lastException = ex;
            } finally {
                logger.error("{}-Ignore-retry to license_issue_fz before license={};trace={}", filename, result, trace, lastException);
            }

            result = this.jtlzComponent.license_issue(item_code, content);
        }

        //新内容写入前缀为OUT|的文件
        boolean rt = false;
        if (outputFile || true) {
            rt = FtpWriteUtil.uploadBase64(FileWriteConfig.getFilePath(), outFilename, result);
        }

        return JTLZResponseValueEDI.create(
                outFilename,
                result,
                rt
        );
    }

    protected void jtlzFzServer(String filename, String content){
        String outFilename = filename.replace("IN-","OUT-");
        String[] arr = filename.split("-");
        String item_code = arr[3];

        String result = this.jtlzComponent.license_issue_fz(item_code,content);
        //新内容写入前缀为OUT|的文件
        FtpWriteUtil.uploadBase64(FileWriteConfig.getFilePath(), outFilename, result);
    }
}
