package com.bcxin.backend.documentSignatrures.impls;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.backend.core.exceptions.SaasNofoundException;
import com.bcxin.backend.documentSignatrures.DocumentSignatureProvider;
import com.bcxin.backend.documentSignatrures.SignatureConfigProperty;
import com.bcxin.backend.documentSignatrures.valueTypes.DocumentFileValueType;
import com.bcxin.backend.documentSignatrures.valueTypes.DocumentSignatureResult;
import com.bcxin.backend.domain.enums.DocumentType;
import com.bcxin.backend.domain.models.SignatureQueuesDocument;
import com.bcxin.backend.domain.repositories.SignatureQueuesDocumentRepository;
import com.bcxin.backend.utils.DocumentFileUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ntp.TimeStamp;
import org.slf4j.Logger;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;

public abstract class DocumentSignatureProviderAbstract implements DocumentSignatureProvider {
    protected final SignatureConfigProperty configProperty;
    private final SignatureQueuesDocumentRepository signatureQueuesDocumentRepository;

    protected final JdbcTemplate jdbcTemplate;

    protected DocumentSignatureProviderAbstract(SignatureConfigProperty configProperty,
                                                SignatureQueuesDocumentRepository signatureQueuesDocumentRepository,
                                                JdbcTemplate jdbcTemplate) {
        this.configProperty = configProperty;
        this.signatureQueuesDocumentRepository = signatureQueuesDocumentRepository;
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public void step1_push2Queue() {
        DocumentType[] list = DocumentType.values();
        for (DocumentType documentType : list) {
            String querySql = documentType.getSelectSql();
            if (StringUtils.isEmpty(querySql)) {
                getLogger().warn("无需签章:documentType={};sql={}", documentType.getName(), querySql);
                continue;
            }

            try {
                 List<DocumentFileValueType> documentFiles =
                        jdbcTemplate.query(querySql, new RowMapper<DocumentFileValueType>() {
                            @Override
                            public DocumentFileValueType mapRow(ResultSet rs, int rowNum) throws SQLException {
                                DocumentFileValueType row = new DocumentFileValueType();
                                row.setBusiness_id(rs.getString("business_id"));
                                row.setPath(rs.getString("path"));
                                return row;
                            }
                        });

                getLogger().warn(
                        "========> step1_push2Queue:添加待签章的文书数据documentType={}, size={}; ",
                        documentType.getName(), documentFiles.size()
                );

                for (DocumentFileValueType documentFile : documentFiles) {
                    try {
                        String path = getPath(documentFile.getPath());
                        if (StringUtils.isEmpty(path)) {
                            getLogger().error("当前documentFile的Path无效:{}", path);

                            continue;
                        }

                        String businessId = documentFile.getBusiness_id();
                        SignatureQueuesDocument document =
                                signatureQueuesDocumentRepository.getSignatureQueuesDocument(businessId, documentType.getValue() + "");

                        getLogger().warn("========> step1_push2Queue 验证队列中是否存在:businessId={}, type={}; path={}; document存在={}",
                                businessId, documentType.getValue(), path, (document != null)?"严重-非预期":"预期");
                        if (document == null) {
                            document = new SignatureQueuesDocument();
                            document.setCreated(new Date());
                            document.setLastmodified(new Date());
                            document.setStatus(0);
                            document.setStamp_xy(documentType.getStampXy());
                            document.setBusiness_name(documentType.getName());
                            document.setBusiness_id(businessId);
                            document.setBusiness_type(documentType.getValue() + "");
                            document.setFile_url(path);
                            // 其他必要的初始化操作
                            signatureQueuesDocumentRepository.save(document);
                        } else {
                            //文书地址不一致重置记录重新签章靓证
                            if (!document.getFile_url().contains(path)) {
                                signatureQueuesDocumentRepository.resetDocumentPath(0, new Date(), path, "废止", document.getId());
                            }
                        }
                    } catch (Exception ex) {
                        getLogger().error("createDocumentSignature_old 处理签章事项; businessId={};path={}", documentFile.getBusiness_id(), documentFile.getPath(), ex);
                    }
                }
            } catch (Exception ex) {
                getLogger().error("step1_push2Queue 异常:documentType={}; querySql={}", documentType.getName(), querySql, ex);
            }
        }
    }


    @Override
    public void step2_doSignature() {
        List<SignatureQueuesDocument> list = signatureQueuesDocumentRepository.pageQueues(0, PageRequest.of(0, 80)).getContent();
        for (SignatureQueuesDocument document : list) {
            try {
                DocumentSignatureResult result = documentQuicklyServer(document);
                if (result!=null && result.isSuccess()) {
                    signatureQueuesDocumentRepository.updateSignatureQueuesDocument(1, new Date(), "文书签章成功", "废止", document.getId());
                }
                else if(result!=null && !result.isFileExists()) {
                    /**
                     * 针对找不到文件的情况, 进行删除处理
                     */
                    signatureQueuesDocumentRepository.updateSignatureQueuesDocument(4, new Date(),
                            result.getMessage(),
                            document.getId());
                }
                else {
                    signatureQueuesDocumentRepository.updateSignatureQueuesDocument(2, new Date(),
                            String.format("文书签章失败:%s", result.getMessage()),
                            document.getId());
                }
            } catch (SaasNofoundException ex) {
                signatureQueuesDocumentRepository.updateSignatureQueuesDocument(2, new Date(), "404-" + ex.getMessage(), document.getId());
                getLogger().error("updateDocumentSignature_old: 404 document.id={}; status={}, fileUrl={}",
                        document.getId(), document.getStatus(), document.getFile_url(), ex);
            } catch (Exception ex) {
                signatureQueuesDocumentRepository.updateSignatureQueuesDocument(2, new Date(), "文书签章失败:" + ex.getMessage(), document.getId());
                getLogger().error("updateDocumentSignature_old: document.id={}; status={}, fileUrl={}",
                        document.getId(), document.getStatus(), document.getFile_url(), ex);
            }
        }
    }

    @Override
    public void step3_doExceptionData() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR, -2);

        signatureQueuesDocumentRepository.deleteNonDocumentSignatureQueues(calendar.getTime());
    }

    protected abstract Logger getLogger();

    protected String getPath(String path) {
        if (StringUtils.isEmpty(path)) {
            return "";
        }
        try {
            JSONArray array = JSONArray.parseArray(path);
            return array.stream().map(ii -> ((JSONObject) ii).getString("path"))
                    .filter(ii -> !StringUtils.isEmpty(ii))
                    .findFirst().orElse(null);
        } catch (Exception ex) {
            getLogger().error("无效的文书地址数据:path={}", path);
            return "";
        }
    }

    protected DocumentSignatureResult documentQuicklyServer(SignatureQueuesDocument document) throws Exception {
        String rootPath = configProperty.getRootPath();
        String tempPDF = configProperty.getTempPDF();
        StringBuilder logTrace = new StringBuilder();
        String traceId = UUID.randomUUID().toString();
        try {
            String stamp_xy = document.getStamp_xy();
            String filePath = document.getFile_url();
            String p = rootPath + filePath;
            Path path = Paths.get(p);
            String filename = String.format("%s_%s", document.getId(), path.getFileName().toString());
            String documentIn = tempPDF.replace("temp", "in") + "/document";
            String inFile = rootPath + documentIn + "/" + filename;
            // 将字符串路径转换为Path对象
            Path sourcePath = Paths.get(p);
            Path sourceInPath = Paths.get(inFile);
            // 使用Files.copy方法复制文件
            try {
                Files.copy(sourcePath, sourceInPath, StandardCopyOption.REPLACE_EXISTING);
                logTrace.append(String.format("复制文件sourcePath=%s; sourceInPath=%s", sourcePath, sourceInPath));
            } catch (IOException e) {
                if(!sourcePath.toFile().exists()) {
                    DocumentSignatureResult result = DocumentSignatureResult.create(
                            false,
                            String.format("找不到原文件:%s", sourcePath)
                    );

                    result.assignNotExists();

                    return result;
                }

                getLogger().error("{}-异常-复制文件(SignatureQueuesDocument.Id={})sourcePath={}; sourceInPath={}", traceId, document.getId(), sourcePath, sourceInPath, e);
                throw new SaasNofoundException("找不到原文件");
            }

            //String documentOut = tempPDF.replace("temp", "out") + "/document";
            //String documentOut = configProperty.getDocumentOutPath();
            //String outRelativePath = documentOut + "/" + filename;
            String outRelativePath = configProperty.getDocumentOutPath(filename);
            String outFile = rootPath + outRelativePath;
            //2.调用接口，激活电子印章签验接口服务器完成签章
            boolean boo = activateXMPDocumentQuicklyExCGI(stamp_xy);

            logTrace.append(String.format("执行activateXMPDocumentQuicklyExCGI的结果: boo=%s", boo));
            //3.判断返回结果，如果失败，删除/uploads/pdf/dianziqianzhang/in/document 目录下对应名称的文件，然后返回false，
            try {
                Files.delete(sourceInPath);

                logTrace.append(String.format("SourceInPath(%s)文件删除成功;", sourceInPath));
            } catch (IOException e) {
                getLogger().error("{}-删除(SignatureQueuesDocument.Id={})sourceInPath={} 发生异常", traceId, document.getId(), sourceInPath, e);
            }

            if (!boo) {
                return DocumentSignatureResult.create(boo, "签章失败");
            }

            /**
             * 针对: 无效签章的更改状态及返回错误信息
             */
            Path sourceOutPath = Paths.get(outFile);
            // 检查签章是否存在
            boolean hasRedSeal = DocumentFileUtil.checkPdfForRedSeal(
                    configProperty.getRootPath(),
                    outRelativePath);
            if (!hasRedSeal) {
                logTrace.append(String.format("重新核验文书之后;发现签章无效:%s;", outRelativePath));
                Path errorPath = Paths.get(configProperty.getDocumentErrorPath(filename));
                Files.move(sourceOutPath, errorPath);
                return DocumentSignatureResult.create(false, "签章后还是无有效章");
            }

            //4.如果成功，读取文件路径为/uploads/pdf/dianziqianzhang/out/document/xxx.pdf 文件重新写入filepath
            try {
                Files.copy(sourceOutPath, sourcePath, StandardCopyOption.REPLACE_EXISTING);
                logTrace.append(String.format("复制签章成功后的文件: sourceOutPath = %s, sourceInPath=%s; sourcePath=%s;", sourceOutPath, sourceInPath, sourcePath));
            } catch (IOException e) {
                getLogger().error("{}-异常: 复制documentQuicklyServer(SignatureQueuesDocument.Id={})签章成功后的文件(exists={}): sourceOutPath = {}, sourceInPath={}; sourcePath={}",
                        traceId,
                        document.getId(),
                        Files.exists(sourceOutPath),
                        sourceOutPath, sourceInPath, sourcePath, e);
            }

            try {
                Files.delete(sourceOutPath);

                logTrace.append(String.format("sourceOutPath(%s) 文件删除成功;", sourceOutPath));
            } catch (IOException e) {
                getLogger().error("{} 异常: 删除 (SignatureQueuesDocument.Id={})sourceOutPath={} 异常", traceId, document.getId(), sourceOutPath, e);
            }

            //6.然后返回true
            return DocumentSignatureResult.create(boo, "签章成功");
        } finally {
            getLogger().error("{}-documentQuicklyServer 跟踪信息:{}", traceId, logTrace);
        }
    }

    protected abstract boolean activateXMPDocumentQuicklyExCGI(String stamp_xy) throws Exception;
}
