package com.bcxin.backend.domain.signature.service.impls;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.backend.core.edis.EDIConstants;
import com.bcxin.backend.core.exceptions.SaasBadException;
import com.bcxin.backend.domain.enums.DocumentType;
import com.bcxin.backend.domain.models.SignatureQueuesDTO;
import com.bcxin.backend.domain.models.SignatureQueuesDocument;
import com.bcxin.backend.domain.repositories.SignatureQueuesDocumentRepository;
import com.bcxin.backend.domain.repositories.SignatureQueuesRepository;
import com.bcxin.backend.domain.signature.service.BeiJingInJTLZSignature;
import com.bcxin.backend.domain.utils.FileUtils;
import com.bcxin.backend.domain.utils.JTLZBodyUtil;
import com.google.common.collect.Maps;
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <b> 北京京通靓证业务 </b>
 * @author ZXF
 * @create 2024/12/16 0016 11:08
 * @version
 * @注意事项 </b>
 */
@Slf4j
@Service
public class BeiJingInJTLZServiceImpl implements BeiJingInJTLZSignature {
    private static final Logger logger = LoggerFactory.getLogger(BeiJingInJTLZServiceImpl.class);

    private final SignatureQueuesDocumentRepository signatureQueuesDocumentRepository;
    private final SignatureQueuesRepository signatureQueuesRepository;
    @Value("${myapps.domain.url}")
    String urlHead;
    @Value("${myapps.storage.root}")
    String rootPath;
    @Value("${myapps.signature.ferry_outside}")
    String ferryOutside;//外网进来文件存放地址
    @Value("${myapps.signature.ferry_inside}")
    String ferryInside;//内网出去文件存放地址

    @Autowired
    @Qualifier("primaryJdbcTemplate")
    protected JdbcTemplate jdbcTemplate;

    private final HttpClient httpClient;
    private final ThreadPoolTaskExecutor taskExecutor;
    public BeiJingInJTLZServiceImpl(SignatureQueuesDocumentRepository signatureQueuesDocumentRepository,
                                    SignatureQueuesRepository signatureQueuesRepository, HttpClient httpClient,
                                    ThreadPoolTaskExecutor taskExecutor) {
        this.signatureQueuesDocumentRepository = signatureQueuesDocumentRepository;
        this.signatureQueuesRepository = signatureQueuesRepository;
        this.httpClient = httpClient;
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void initJTLZ() {
        //创建京通靓证数据上送ftp输出到外网
        try {
            createJTLZ();
        } catch (Exception e) {
            logger.error("initJTLZ 京通靓证信息", e);
        }
    }

    @Override
    public void initJTLZDocument() {
        //创建京通靓证许可证数据输出到外网
        try{
            createJTLZDocument();
        }catch (Exception e){
            logger.error("initJTLZDocument 京通靓证信息", e);
        }
    }

    @Override
    public void initJTLZFZ() {
        //已靓证证书编号发起废止
        try{
            createJTLZFZ();
        }catch (Exception e){
            logger.error("initJTLZFZ 京通靓证信息", e);
        }

    }

    @Override
    public void useJTLZ() {
        //读取政务网上送ftp输出到内网目录的处理结果，对结果进行处理
        updateJTLZ();
    }

    @Override
    public void useJTLZFZ() {
        //读取政务网上送ftp输出到内网目录的靓证废止处理结果，对结果进行处理
        updateJTLZFZ();
    }

    /**
     * <b> 批量插入符合签章条件的文书记录 </b>
     * @author ZXF
     * @create 2022/10/31 0031 13:33
     * @version
     * @注意事项 </b>
     */
    private void createJTLZ() {
        StopWatch stopWatch = new StopWatch();
        Exception lastException = null;
        StringBuilder sb = new StringBuilder();
        try {
            stopWatch.start();
            //最后修改时间在5分钟内的通过记录 TODO 当前只查询资格证数据处理，还需要查询保安服务许可证数据
            Page<SignatureQueuesDTO> pageQueues =
                    signatureQueuesRepository.pageQueuesBy5Minute(1, PageRequest.of(0, 150));
            List<SignatureQueuesDTO> queues = pageQueues.getContent();
            Snowflake snowflake = IdUtil.createSnowflake(1, 1);
            Collection<String> processedFileNames = new ArrayList<>();
            AtomicInteger errorCountRef = new AtomicInteger(0);
            sb.append(String.format("获取到的JTLZ数量=%s;", queues.size()));

            CountDownLatch downLatch = new CountDownLatch(queues.size());
            for (SignatureQueuesDTO dto : queues) {
                this.taskExecutor.execute(() -> {
                    try {
                        if (StringUtils.isEmpty(dto.getData()) || StringUtils.isEmpty(dto.getBusiness_id())) {
                            throw new SaasBadException("签章记录数据缺失");
                        }
                        String sql = "SELECT item_attachment FROM tlk_certificate WHERE id = '" + dto.getBusiness_id() + "';";
                        List<String> attachment = jdbcTemplate.query(sql, new RowMapper<String>() {
                            @Override
                            public String mapRow(ResultSet rs, int rowNum) throws SQLException {
                                return rs.getString("item_attachment");
                            }
                        });

                        if (attachment.size() == 0 || StringUtils.isEmpty(attachment.get(0))) {
                            signatureQueuesRepository.updateSignature(0, new Date(), "原电子证书文件丢失，重新签章", dto.getId());
                            return;
                        }
                        String pdfUrl = urlHead + attachment.get(0);
                        String path = rootPath + attachment.get(0);
                        Path path1 = Paths.get(path);
                        String fileName = path1.getFileName().toString();
                        String extension = "";
                        int dotIndex = fileName.lastIndexOf('.');
                        if (dotIndex != -1) {
                            extension = fileName.substring(dotIndex + 1);
                        }

                        String base64 = FileUtils.urlToBase64(httpClient, pdfUrl);
                        if (StringUtils.isEmpty(base64)) {
                            throw new SaasBadException("电子证书转换base64失败：" + pdfUrl);
                        }
                        SignatureData signatureData = JSONObject.parseObject(dto.getData(), SignatureData.class);
                        JSONObject data_field = new JSONObject();
                        data_field.put("ZZMC", "中华人民共和国保安员证");
                        data_field.put("CYRMC", signatureData.getName());
                        data_field.put("FZJGZZJGDM", "1111000000002888XF");//发证机构唯一标识
                        data_field.put("FZJGSSXZQHDM", "110000");//发证机构所属行政区划代码
                        data_field.put("CYRSFZJLX", "10");
                        data_field.put("CYRSFZJHM", signatureData.getIdcardno().toUpperCase());
                        data_field.put("FZRQ", DateUtil.formatDate(DateUtil.parseDate(signatureData.getFzDate())));
                        data_field.put("YXQJSRQ", "");
                        data_field.put("CSRQ", signatureData.getYear() + "年" + signatureData.getMonth() + "月" + signatureData.getDay() + "日");
                        data_field.put("ZZ", signatureData.getAddress());
                        data_field.put("ZP", "");
                        data_field.put("ZZHM", signatureData.getCertificateno());
                        data_field.put("FZJGMC", StringUtils.isEmpty(signatureData.getCertificatefrom()) ? "北京市公安局" : signatureData.getCertificatefrom());
                        log.info("========> createJTLZ.SignatureQueuesDTO：data_field：{}", JSON.toJSONString(data_field));
                        OperatorData operatorData = OperatorData.fixedOperatorData();
                        List<FileData> fileDataList = new ArrayList<>();
                        fileDataList.add(new FileData(fileName, extension, base64, "附件为" + signatureData.getName() + "（编号：" + signatureData.getCertificateno() + "）的电子资格证。"));

                        String bodyContent =
                                license_issue(
                                        EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_CERTIFICATE_SERVICE_CODE,
                                        EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_CERTIFICATE_SERVICE_NAME,
                                        EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_CERTIFICATE_SEAL_CODE,
                                        data_field, operatorData,
                                        fileDataList);
                        // 内到外文件名规则：IN-JTLZ-01-1111-101.bcx（内网-京通靓证-资格证编码-itemcode-业务id）
                        String fName = EDIConstants.getJTLZFileName(String.valueOf(dto.getId()), snowflake.nextIdStr());
                        processedFileNames.add(fName);
                        FileUtils.writeFile(ferryInside, fName, bodyContent);
                        signatureQueuesRepository.updateResult(new Date(), "靓证中", dto.getId());
                    } catch (Exception e) {
                        errorCountRef.incrementAndGet();
                        logger.error("========> createJTLZ.SignatureQueuesDTO.server.error: 【ID:{}】", dto.getId(), e);
                    } finally {
                        downLatch.countDown();
                    }
                });
            }

            try {
                downLatch.await();
            } catch (Exception ex) {
                logger.error("downLatch.await() exception", ex);
            }

            sb.append(String.format("errorSize=%s;", errorCountRef.get()));
            if (processedFileNames.size() > 0) {
                String writeFtpName = EDIConstants.getSummaryFileName();
                String body = String.join(",", processedFileNames);
                log.error("========> createJTLZ.file：writeFtpName：" + writeFtpName + " ，文件个数: " + processedFileNames.size() + " ---");
                FileUtils.writeFile(ferryInside, writeFtpName, body);
            }
        } catch (Exception ex) {
            lastException = ex;
            throw ex;
        } finally {
            stopWatch.stop();

            logger.error("{}-Done for createJTLZ.SignatureQueuesDTO cost{} seconds; trace={}",
                    (lastException == null ? "Success" : "Error"),
                    stopWatch.getTotalTimeSeconds(), sb, lastException);
        }
    }

    /**
     * <b> 保安服务许可证靓证 </b>
     * @author ZXF
     * @create 2022/10/31 0031 13:33
     * @version
     * @注意事项 </b>
     */
    private void createJTLZDocument() {
        Page<SignatureQueuesDocument> pageDocumentQueues = signatureQueuesDocumentRepository.pageQueuesBy5Minute(1, PageRequest.of(0, 30));
        List<SignatureQueuesDocument> documentQueues = pageDocumentQueues.getContent();
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        log.error("========> createJTLZDocument.size: {}", documentQueues.size());
        CountDownLatch countDownLatch = new CountDownLatch(documentQueues.size());
        Collection<String> processedFileNames = new ArrayList<>();
        for (SignatureQueuesDocument dto : documentQueues) {
            this.taskExecutor.execute(() -> {
                try {
                    SignatureQueuesDocument documentQueueF;
                    String sql = "";
                    if ("15".equals(dto.getBusiness_type())) {
                        sql = "SELECT b.item_comname,a.item_legalCardnumber,b.item_comaddress,b.item_legalname,b.item_fwfw,DATE_FORMAT(b.item_clrq, '%Y-%m-%d') AS item_clrq,DATE_FORMAT(b.item_fzrq, '%Y-%m-%d') AS item_fzrq,b.item_pzwh,b.item_certificatenum,b.item_organname,b.item_registeredcapital,a.item_security_z_file,a.item_security_f_file FROM tlk_securitysevicek a,tlk_companycertificate b WHERE a.id = b.ITEM_SOURCE_ID AND LENGTH(a.item_security_z_file)>0 AND LENGTH(a.item_security_f_file)>0 AND a.id = '" + dto.getBusiness_id() + "';";
                        documentQueueF = signatureQueuesDocumentRepository.getSignatureQueuesDocument(dto.getBusiness_id(), "16");
                    } else if ("25".equals(dto.getBusiness_type())) {
                        sql = "SELECT b.item_comname,a.ITEM_LEGAL_CARD_NUM item_legalCardnumber,b.item_comaddress,b.item_legalname,b.item_fwfw,DATE_FORMAT(b.item_clrq, '%Y-%m-%d') AS item_clrq,DATE_FORMAT(b.item_fzrq, '%Y-%m-%d') AS item_fzrq,b.item_pzwh,b.item_certificatenum,b.item_organname,b.item_registeredcapital,a.item_security_z_file,a.item_security_f_file FROM tlk_scope_namechanges a,tlk_companycertificate b WHERE a.id = b.ITEM_SOURCE_ID AND LENGTH(a.item_security_z_file)>0 AND LENGTH(a.item_security_f_file)>0 AND a.id = '" + dto.getBusiness_id() + "';";
                        documentQueueF = signatureQueuesDocumentRepository.getSignatureQueuesDocument(dto.getBusiness_id(), "26");
                    } else if ("45".equals(dto.getBusiness_type())) {
                        sql = "SELECT b.item_comname,a.ITEM_APPOINTMENTLEGALCARDNUMBER item_legalCardnumber,b.item_comaddress,b.item_legalname item_legalname,b.item_fwfw,DATE_FORMAT(b.item_clrq, '%Y-%m-%d') AS item_clrq,DATE_FORMAT(b.item_fzrq, '%Y-%m-%d') AS item_fzrq,b.item_pzwh,b.item_certificatenum,b.item_organname,b.item_registeredcapital,a.item_security_z_file,a.item_security_f_file FROM tlk_legalchangek a,tlk_companycertificate b WHERE a.id = b.ITEM_SOURCE_ID AND LENGTH(a.item_security_z_file)>0 AND LENGTH(a.item_security_f_file)>0 AND a.id = '" + dto.getBusiness_id() + "';";
                        documentQueueF = signatureQueuesDocumentRepository.getSignatureQueuesDocument(dto.getBusiness_id(), "46");
                    } else if ("55".equals(dto.getBusiness_type())) {
                        sql = "SELECT b.item_comname,a.ITEM_LEGAL_CARD_NUM item_legalCardnumber,b.item_comaddress,b.item_legalname,b.item_fwfw,DATE_FORMAT(b.item_clrq, '%Y-%m-%d') AS item_clrq,DATE_FORMAT(b.item_fzrq, '%Y-%m-%d') AS item_fzrq,b.item_pzwh,b.item_certificatenum,b.item_organname,b.item_registeredcapital,a.item_security_z_file,a.item_security_f_file FROM tlk_scope_addresschangek a,tlk_companycertificate b WHERE a.id = b.ITEM_SOURCE_ID AND LENGTH(a.item_security_z_file)>0 AND LENGTH(a.item_security_f_file)>0 AND a.id = '" + dto.getBusiness_id() + "';";
                        documentQueueF = signatureQueuesDocumentRepository.getSignatureQueuesDocument(dto.getBusiness_id(), "56");
                    } else if ("65".equals(dto.getBusiness_type())) {
                        sql = "SELECT b.item_comname,a.ITEM_LEGALIDCARDNUMBER item_legalCardnumber,b.item_comaddress,b.item_legalname,b.item_fwfw,DATE_FORMAT(b.item_clrq, '%Y-%m-%d') AS item_clrq,DATE_FORMAT(b.item_fzrq, '%Y-%m-%d') AS item_fzrq,b.item_pzwh,b.item_certificatenum,b.item_organname,b.item_registeredcapital,a.item_security_z_file,a.item_security_f_file FROM tlk_securityservicelicensechange a,tlk_companycertificate b WHERE a.id = b.ITEM_SOURCE_ID AND LENGTH(a.item_security_z_file)>0 AND LENGTH(a.item_security_f_file)>0 AND a.id = '" + dto.getBusiness_id() + "';";
                        documentQueueF = signatureQueuesDocumentRepository.getSignatureQueuesDocument(dto.getBusiness_id(), "66");
                    } else {
                        return;
                    }

                    List<Map<String, String>> attachment = jdbcTemplate.query(sql, new RowMapper<Map<String, String>>() {
                        @Override
                        public Map<String, String> mapRow(ResultSet rs, int rowNum) throws SQLException {
                            Map<String, String> map = Maps.newHashMap();
                            map.put("item_comname", rs.getString("item_comname"));
                            map.put("item_legalCardnumber", rs.getString("item_legalCardnumber").trim());
                            map.put("item_comaddress", rs.getString("item_comaddress"));
                            map.put("item_legalname", rs.getString("item_legalname"));
                            map.put("item_fwfw", formatManagement(rs.getString("item_fwfw")));
                            map.put("item_clrq", rs.getString("item_clrq"));
                            map.put("item_fzrq", rs.getString("item_fzrq"));
                            map.put("item_pzwh", rs.getString("item_pzwh"));
                            map.put("item_certificatenum", rs.getString("item_certificatenum"));
                            map.put("item_organname", rs.getString("item_organname"));
                            map.put("item_registeredcapital", rs.getString("item_registeredcapital"));
                            map.put("item_security_z_file", rs.getString("item_security_z_file"));
                            map.put("item_security_f_file", rs.getString("item_security_f_file"));
                            return map;
                        }
                    });
                    if (attachment.size() == 0 || attachment.get(0) == null) {
                        throw new SaasBadException("证书记录不存在");
                    }
                    Map<String, String> attachmentMap = attachment.get(0);
                    String item_security_z_file = dto.getFile_url();
                    String item_security_f_file = documentQueueF.getFile_url();

                    if (StringUtils.isEmpty(item_security_z_file) || StringUtils.isEmpty(item_security_f_file)) {
                        throw new SaasBadException("电子证书地址不存在");
                    }
                    if (StringUtils.isEmpty(attachmentMap.get("item_legalCardnumber"))) {
                        throw new SaasBadException("法人身份证号不存在");
                    }

                    String pathZ = rootPath + item_security_z_file;
                    String pathF = rootPath + item_security_f_file;
                    //合并正副本
                    String fileName = attachmentMap.get("item_comname") + "（编号：" + attachmentMap.get("item_pzwh") + "）的电子保安服务许可证";
                    String outpdf = rootPath + "/uploads/pdf/documenttemp/" + DateUtil.today() + "/" + fileName + ".pdf";
                    mergePdf(pathZ, pathF, outpdf);
                    //合并后文件转base64
                    String base64 = FileUtils.fileToBase64(outpdf);
                    //删除合并后文件
                    new File(outpdf).delete();

                    if (StringUtils.isEmpty(base64)) {
                        throw new SaasBadException("电子证书正副本合并后转换base64失败：" + outpdf);
                    }

                    String certificatenum = attachmentMap.get("item_certificatenum");
                    if (StringUtils.isNotEmpty(certificatenum)) {
                        if (!certificatenum.contains("京公保服")) {
                            certificatenum = "京公保服" + certificatenum;
                        }
                        if (!certificatenum.contains("号")) {
                            certificatenum = certificatenum + "号";
                        }
                    }

                    JSONObject data_field = new JSONObject();
                    data_field.put("ZZMC", "保安服务许可证");
                    data_field.put("FZJGZZJGDM", "1111000000002888XF");//发证机构唯一标识
                    data_field.put("FZJGSSXZQHDM", "110000");//发证机构所属行政区划代码
                    data_field.put("YXQJSRQ", "");
                    data_field.put("ZZHM", certificatenum);
                    data_field.put("CYRMC", attachmentMap.get("item_comname"));
                    data_field.put("CYRSFZJLX", "80");
                    data_field.put("CYRSFZJHM", attachmentMap.get("item_legalCardnumber"));
                    data_field.put("XKZZJH", certificatenum);
                    data_field.put("FR", attachmentMap.get("item_legalname"));
                    data_field.put("FZJGMC", attachmentMap.get("item_organname"));
                    data_field.put("FZRQ", attachmentMap.get("item_fzrq"));
                    data_field.put("ZS", attachmentMap.get("item_comaddress"));
                    data_field.put("FWFW", attachmentMap.get("item_fwfw"));
                    data_field.put("PZWH", attachmentMap.get("item_pzwh"));
                    data_field.put("ZCZB", StringUtils.isEmpty(attachmentMap.get("item_registeredcapital")) ? "0.00" : attachmentMap.get("item_registeredcapital"));

                    OperatorData operatorData = OperatorData.fixedOperatorData();
                    List<FileData> fileDataList = new ArrayList<>();
                    fileDataList.add(new FileData(fileName + ".pdf", "pdf", base64, fileName));
                    String bodyContent = license_issue(
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_DOCUMENT_CERTIFICATE_SERVICE_CODE,
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_DOCUMENT_CERTIFICATE_SERVICE_NAME,
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_DOCUMENT_CERTIFICATE_SEAL_CODE,
                            data_field, operatorData, fileDataList
                    );
                    String fName =
                            EDIConstants.getJTLZDocumentFileName(String.valueOf(dto.getId()), snowflake.nextIdStr());
                    processedFileNames.add(fName);
                    FileUtils.writeFile(ferryInside, fName, bodyContent);
                } catch (Exception e) {
                    log.error("========> createJTLZDocument.server.error: {} bn={}   ----", dto.getId(), dto.getBusiness_name(), e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }

        try {
            countDownLatch.await();
        } catch (Exception ex) {
            logger.error("countDownLatch waiting", ex);
        }

        if (processedFileNames.size() > 0) {
            String writeFtpName = EDIConstants.getDocumentSummaryFileName();
            String body = String.join(",", processedFileNames);
            log.error("========> createJTLZDocument.file：writeFtpName：{} ，文件个数: {} ---", writeFtpName, processedFileNames.size());
            FileUtils.writeFile(ferryInside, writeFtpName, body);
        }
    }

    /**
     * <b> 2张pdf合并成一张pdf，至少需要一张pdf </b>
     * @param inpdf1 许可证正本绝对路径1
     * @param inpdf2 许可证副本绝对路径2
     * @param outpdf 输出pdf绝对路径
     * @author ZXF
     * @create 2025/02/28 0028 16:01
     * @version
     * @注意事项 </b>
     */
    private static void mergePdf(String inpdf1, String inpdf2, String outpdf) throws Exception {
        if (StringUtils.isEmpty(inpdf1)) {
            throw new FileNotFoundException("Font file not found: " + inpdf1);
        }
        File file = new File(outpdf);
        if (!file.exists()) {
            FileUtils.touch(file);
        }
        Document document = new Document(); // 横向A4纸
        PdfCopy copy = null;
        try {
            copy = new PdfCopy(document, new FileOutputStream(outpdf));
            document.open();
            PdfReader reader1 = new PdfReader(inpdf1);
            PdfImportedPage page1 = copy.getImportedPage(reader1, 1);
            copy.addPage(page1);
            if (StringUtils.isNotEmpty(inpdf2)) {
                document.newPage();
                PdfReader reader2 = new PdfReader(inpdf2);
                PdfImportedPage page2 = copy.getImportedPage(reader2, 1);
                copy.addPage(page2);
            }
        } finally {
            document.close();

            if (copy != null) {
                copy.close();
            }
        }
    }

    /**
     * <b> 经营范围转换 </b>
     * @author ZXF
     * @create 2024/12/25 0025 11:12
     * @version
     * @注意事项 </b>
     */
    private String formatManagement(String fwfw) {
        if (StringUtils.isEmpty(fwfw)) {
            return "";
        }
        StringBuffer management = new StringBuffer();
        //服务范围打印顺序  /*门卫  巡逻 守护 押运 随身护卫 安全检查 安全技术防范 安全风险评估 区域秩序维护 */
        String[] orders = new String[]{"01", "02", "03", "04", "05", "06", "07", "08", "09"};
        String[] ss = fwfw.split(";");
        for (int j = 0; j < orders.length; j++) {
            for (int i = 0; i < ss.length; i++) {
                if (orders[j].equals(ss[i])) {
                    if ("01".equals(ss[i])) {
                        management.append("门卫、");
                    } else if ("02".equals(ss[i])) {
                        management.append("巡逻、");
                    } else if ("03".equals(ss[i])) {
                        management.append("守护、");
                    } else if ("05".equals(ss[i])) {
                        management.append("随身护卫、");
                    } else if ("04".equals(ss[i])) {
                        management.append("武装押运、");
                    } else if ("07".equals(ss[i])) {
//                        management.append("区域秩序维护、");
                    } else if ("05".equals(ss[i])) {
                        management.append("安全检查、");
                    } else if ("08".equals(ss[i])) {
                        management.append("安全风险评估、");
                    } else if ("09".equals(ss[i])) {
                        management.append("安全技术防范、");
                    } else if ("10".equals(ss[i])) {
//                        management.append("其他");
                    }
                }

            }
        }
        return management.toString().substring(0, management.toString().length() - 1);
    }

    /**
     * <b> 京通靓证同步报文业务组装 </b>
     * @author ZXF
     * @create 2024/11/20 0020 17:33
     * @version
     * @注意事项 </b>
     */
    private String license_issue(String serviceCode,String serviceName,String sealCode,JSONObject data_field,OperatorData operatorData,List<FileData> fileDataList) {
        // 生成 token 的逻辑
        String license_code = "";
        try {
            JSONObject data = new JSONObject();
            JSONObject json = new JSONObject();
            json.put(EDIConstants.PARAM_API_LIANG_ZHENG_SERVICE_ITEM_CODE, serviceCode);// 事项编码
            json.put(EDIConstants.PARAM_API_LIANG_ZHENG_SERVICE_ITEM_NAME, serviceName);//事项名称
            json.put("license_group", "组别1");//照面模版组别名称
            json.put(EDIConstants.PARAM_API_LIANG_ZHENG_BIZ_NUM, UUID.randomUUID().toString());
            JSONObject operator = new JSONObject();
            operator.put("account", operatorData.getAccount());
            operator.put("name", operatorData.getName());
            operator.put("identity_num", operatorData.getIdcardno());
            operator.put("role", operatorData.getRoleName());
            operator.put("service_org", operatorData.getOrgName());
            operator.put("division", operatorData.getRegionName());
            operator.put("division_code", operatorData.getRegionCode());
            json.put("operator", operator);
            json.put("data_fields", data_field);
            json.put("seal_code", sealCode);//章编码
            json.put("sign_attach", false);
            JSONArray attachments = new JSONArray();
            JSONObject attachment;
            for (FileData fileData : fileDataList){
                attachment = new JSONObject();
                attachment.put("is_show_template", "true");
                attachment.put("is_license_image", "true");
                attachment.put("file_type", fileData.getFiletype());
                attachment.put("name", fileData.getFilename());
                attachment.put("description", fileData.getDescription());
                attachment.put("file_data", fileData.getFilebase64());
                attachments.add(attachment);
            }
            json.put("attachments", attachments);
            data.put("data", json);
            String body = data.toJSONString();

            return body;
        } catch (Exception e) {
            log.error("====> 京通靓证信息推送定时任务.license_issue.error:", e);
            return license_code;
        }
    }

    /**
     * <b> 已靓证证书发起 废止 </b>
     * @author ZXF
     * @create 2022/10/31 0031 13:33
     * @version
     * @注意事项 </b>
     */
    private void createJTLZFZ() {
        //最后修改时间在5分钟内的通过记录 TODO 当查询jt_code=废止的记录
        Page<SignatureQueuesDTO> pageQueues = signatureQueuesRepository.pageQueuesByCodeFZ(1, PageRequest.of(0, 30));
        List<SignatureQueuesDTO> queues = pageQueues.getContent();
        Collection<String> processedFileNames = new ArrayList<>();
        CountDownLatch downLatch = new CountDownLatch(queues.size());
        for (SignatureQueuesDTO dto : queues) {
            this.taskExecutor.execute(() -> {
                try {
                    if (StringUtils.isEmpty(dto.getData()) || StringUtils.isEmpty(dto.getBusiness_id())) {
                        throw new Exception("签章记录数据缺失");
                    }
                    SignatureData signatureData = JSONObject.parseObject(dto.getData(), SignatureData.class);
                    String bodyContent = JTLZBodyUtil.license_issue_fz(
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_CERTIFICATE_SERVICE_CODE,
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_CERTIFICATE_SERVICE_NAME,
                            signatureData.getCertificateno());
                    // 内到外文件名规则：IN-JTLZ-01-1111-101.bcx（内网-京通靓证-资格证编码-itemcode-业务id）
                    String fName = EDIConstants.getJTLZ_FZ_FileName(String.valueOf(dto.getId()));
                    processedFileNames.add(fName);
                    FileUtils.writeFile(ferryInside, fName, bodyContent);
                } catch (Exception e) {
                    log.error("========> createJTLZFZ.SignatureQueues.server.error: " + e.getMessage() + "    ----");
                } finally {
                    downLatch.countDown();
                }
            });
        }

        try {
            downLatch.await();
        } catch (Exception ex) {
            logger.error("等待废止执行完毕", ex);
        }


        Page<SignatureQueuesDocument> pageDocumentQueues = signatureQueuesDocumentRepository.pageQueuesByCodeFZ(1, PageRequest.of(0, 30));
        List<SignatureQueuesDocument> documentQueues = pageDocumentQueues.getContent();

        log.error("========> createJTLZFZ.documentQueues.size: " + documentQueues.size());
        CountDownLatch documentCountDownLatch = new CountDownLatch(documentQueues.size());
        for (SignatureQueuesDocument dto : documentQueues) {
            this.taskExecutor.execute(() -> {
                try {
                    DocumentType dt = DocumentType.getByValue(Integer.parseInt(dto.getBusiness_type()));
                    String sql = "SELECT b.item_certificatenum FROM " + dt.getTableName() + " a,tlk_companycertificate b WHERE a.id = b.ITEM_SOURCE_ID AND a.id = '" + dto.getBusiness_id() + "';";
                    List<String> certificatenums = jdbcTemplate.query(sql, new RowMapper<String>() {
                        @Override
                        public String mapRow(ResultSet rs, int rowNum) throws SQLException {
                            return rs.getString("item_certificatenum");
                        }
                    });
                    if (certificatenums.size() == 0 || certificatenums.get(0) == null) {
                        throw new Exception("无有效证书编号");
                    }
                    String certificatenum = certificatenums.get(0);
                    String bodyContent = license_issue_fz(
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_DOCUMENT_CERTIFICATE_SERVICE_CODE,
                            EDIConstants.CODE_API_LIANG_ZHENG_LICENSE_DOCUMENT_CERTIFICATE_SERVICE_NAME,
                            certificatenum);
                    // 内到外文件名规则：IN-JTLZ-15-1111-101.bcx（内网-京通靓证-保安服务许可证编码-itemcode-业务id）
                    String fName = EDIConstants.getJTLZDocument_FZ_FileName(String.valueOf(dto.getId()));
                    processedFileNames.add(fName);
                    FileUtils.writeFile(ferryInside, fName, bodyContent);
                } catch (Exception e) {
                    log.error("========> createJTLZFZ.SignatureQueuesDocument.server.error: businessId={}; url={}----", dto.getBusiness_id(), dto.getFile_url(), e);
                } finally {
                    documentCountDownLatch.countDown();
                }
            });
        }

        try {
            documentCountDownLatch.await();
        } catch (Exception ex) {
            logger.error("等待废止执行完毕", ex);
        }

        if (processedFileNames.size() > 0) {
            String writeFtpName = EDIConstants.getFZSummaryFileName();
            String body = String.join(",", processedFileNames);
            log.error("========> createJTLZ.file:writeFtpName:" + writeFtpName + " ,body: " + body + " ---");
            FileUtils.writeFile(ferryInside, writeFtpName, body);
        }
        log.error("========> createJTLZ.end ----------------------------------------");
    }

    /**
     * <b> 京通靓证(废止)同步报文业务组装 </b>
     * @author ZXF
     * @create 2024/11/20 0020 17:33
     * @version
     * @注意事项 </b>
     */
    private String license_issue_fz(String serviceCode,String serviceName,String idCode) {
        log.error("====> 京通靓证信息废止定时任务.license_issue_fz.star---------");
        // 生成 token 的逻辑
        String license_code = "";
        try {
            OperatorData operatorData = OperatorData.fixedOperatorData();
            JSONObject data = new JSONObject();
            JSONObject json = new JSONObject();
            json.put("id_code", idCode);// 证照号码
            json.put("service_item_code", serviceCode);// 事项编码
            json.put("service_item_name", serviceName);//事项名称
            json.put("biz_num", UUID.randomUUID().toString());
            JSONObject operator = new JSONObject();
            operator.put("account", operatorData.getAccount());
            operator.put("name", operatorData.getName());
            operator.put("identity_num", operatorData.getIdcardno());
            operator.put("role", operatorData.getRoleName());
            operator.put("service_org", operatorData.getOrgName());
            operator.put("division", operatorData.getRegionName());
            operator.put("division_code", operatorData.getRegionCode());
            json.put("operator", operator);
            data.put("data", json);
            String body = data.toJSONString();
            log.error("====> 京通靓证信息废止定时任务.license_issue_fz.请求报文：" + body);
            return body;
        } catch (Exception e) {
            log.error("====> 京通靓证信息废止定时任务.license_issue_fz.error:" + e.getMessage());
            return license_code;
        }
    }

    /**
     * <b> 解析靓证结果返回 TODO 外到内数据文件未开发 </b>
     * @author ZXF
     * @create 2024/11/27 0027 16:55
     * @version
     * @注意事项 </b>
     */
    private void updateJTLZ(){
        //读取外到内文件
        List<File> files = FileUtils.filenames(ferryOutside, EDIConstants.PUSH_CALLBACK_OUT_FILE_PREFIX);
        log.error("====> 解析靓证结果定时任务.updateJTLZ.files：" + files.size());
        JSONObject json;
        for (File file: files){
            String filename = file.getName();
//          readFtpName文件内容（str）格式：
            String[] arr = filename.replace(EDIConstants.PUSH_FILE_EXTENSION,"").split("-");
            String type = arr[2];
            String id = arr[4];
            if(id.contains("N")){
                id = id.split("N")[0];
            }
            log.error("====> 解析靓证结果定时任务.updateJTLZ.filename：" + filename);
            if(!"01".equals(type) && !"15".equals(type)){
                log.error("====> 解析靓证结果定时任务.updateJTLZ.filename：文件类型不存在");
                continue;
            }
            String content = FileUtil.readString(file, StandardCharsets.UTF_8);
            if(StringUtils.isEmpty(content)){
                log.error("====> 解析靓证结果定时任务.updateJTLZ.fail：type="+type+",id="+id+" end");
                if("01".equals(type)){
                    signatureQueuesRepository.updateJtCode("",new Date(),"靓证失败，请手动设置最后修改时间为当前进行重试",Long.parseLong(id));
                }else if("15".equals(type)){
                    signatureQueuesDocumentRepository.updateJtCode("",new Date(),"靓证失败，请手动设置最后修改时间为当前进行重试",Long.parseLong(id));
                }
                continue;
            }
            log.error("====> 解析靓证结果定时任务.updateJTLZ.result：" + content);
            FileUtil.del(file);
            log.error("====> 解析靓证结果定时任务.updateJTLZ.删除文件：" + filename);
            try{
                json = JSONObject.parseObject(content);
                //失败处理
                if("FAILURE".equals(json.getString("ack_code"))){
                    String errJson = json.getString("errors");
                    if("01".equals(type)){
                        if(errJson.contains("存在重复的电子证照")){
                            //出现重复情况，查询历史有效靓证编号给重复数据赋值
                            String finalId = id;
                            new Thread(()-> {
                                String data = signatureQueuesRepository.getData(finalId);
                                SignatureData signatureData = JSONObject.parseObject(data, SignatureData.class);
                                List<SignatureQueuesDTO> list = signatureQueuesRepository.findByDataLike("%" + signatureData.getCertificateno() + "%");
                                String jtCode = finalId + "YES";
                                for (SignatureQueuesDTO dto1 : list) {
                                    if (StringUtils.isNotEmpty(dto1.getJt_code()) && !dto1.getJt_code().contains("YES")) {
                                        jtCode = dto1.getJt_code();
                                    }
                                }
                                log.error("====> 解析靓证结果定时任务.updateJTLZ.重复的电子证照.jtCode：" + jtCode);
                                for (SignatureQueuesDTO dto1 : list) {
                                    if (StringUtils.isEmpty(dto1.getJt_code()) || dto1.getJt_code().contains("YES")) {
                                        signatureQueuesRepository.updateJtCode(jtCode, new Date(), "完成靓证:存在重复的电子证照（无需重新靓证）", dto1.getId());
                                    }
                                }
                            }).start();
                            continue;
                        }
                        if("[]".equals(errJson)){
                            signatureQueuesRepository.updateJtCode("",new Date(),"靓证失败:异常信息为空",Long.parseLong(id));
                            continue;
                        }
                        JSONArray jsonArray = JSONArray.parseArray(errJson);
                        JSONObject errObj = (JSONObject)jsonArray.get(0);
                        signatureQueuesRepository.updateJtCode("",new Date(),"靓证失败:"+errObj.getString("message"),Long.parseLong(id));
                    }else if("15".equals(type)){
                        if(errJson.contains(EDIConstants.MESSAGE_DUPLICATE_CERTIFICATE_DOCUMENT)){
                            //出现重复情况，查询历史有效靓证编号给重复数据赋值
                            String finalId1 = id;
                            new Thread(()-> {
                                String jtCode = finalId1 + "YES";
                                signatureQueuesDocumentRepository.updateJtCode(jtCode, new Date(), "完成靓证:存在重复的电子证照（无需重新靓证）", Long.parseLong(finalId1));
                            }).start();
                            continue;
                        }
                        if("[]".equals(errJson)){
                            signatureQueuesDocumentRepository.updateJtCode("",new Date(),"靓证失败:异常信息为空",Long.parseLong(id));
                            continue;
                        }
                        JSONArray jsonArray = JSONArray.parseArray(errJson);
                        JSONObject errObj = (JSONObject)jsonArray.get(0);
                        signatureQueuesDocumentRepository.updateJtCode("",new Date(),"靓证失败:"+errObj.getString("message"),Long.parseLong(id));
                    }

                    continue;
                }
                //成功处理
                JSONObject data = json.getObject("data",JSONObject.class);
                String jtcode = data.getString("auth_code");
                if(StringUtils.isEmpty(jtcode)){
                    log.error("====> 解析靓证结果定时任务.updateJTLZ.fail：license_code=null,type="+type+",id="+id+" end");
                    if("01".equals(type)){
                        signatureQueuesRepository.updateJtCode("",new Date(),"靓证失败:靓证编号丢失",Long.parseLong(id));
                    }else if("15".equals(type)){
                        signatureQueuesDocumentRepository.updateJtCode("",new Date(),"靓证失败:靓证编号丢失",Long.parseLong(id));
                    }
                    continue;
                }
                if("01".equals(type)){
                    signatureQueuesRepository.updateJtCode(jtcode,new Date(),"完成靓证",Long.parseLong(id));
                }else if("15".equals(type)){
                    signatureQueuesDocumentRepository.updateJtCode(jtcode,new Date(),"完成靓证",Long.parseLong(id));
                }
                log.error("====> 解析靓证结果定时任务.updateJTLZ.success：end");
            } catch (Exception e){
                log.error("====> 解析靓证结果定时任务.updateJTLZ.fail：" + e.getMessage());
            }
        }
    }

    /**
     * <b> 解析靓证废止结果返回 </b>
     * @author ZXF
     * @create 2024/11/27 0027 16:55
     * @version
     * @注意事项 </b>
     */
    private void updateJTLZFZ(){
        //读取外到内文件
        List<File> files = FileUtils.filenames(ferryOutside,"OUT-JTLZFZ-");
        log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.files：" + files.size());
        JSONObject json;
        for (File file: files){
            String filename = file.getName();
            String[] arr = filename.replace(EDIConstants.PUSH_FILE_EXTENSION,"").split("-");
            String type = arr[2];
            String id = arr[4];
            log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.filename：" + filename);
            if(!"01".equals(type) && !"15".equals(type)){
                log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.filename：文件类型不存在");
                continue;
            }
            String content = FileUtil.readString(file, StandardCharsets.UTF_8);
            if(StringUtils.isEmpty(content)){
                log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.fail：type="+type+",id="+id+" end");
                if("01".equals(type)){
                    signatureQueuesRepository.updateJtCode("废止",new Date(),"靓证废止失败，无有效返回",Long.parseLong(id));
                }else if("15".equals(type)){
                    signatureQueuesDocumentRepository.updateJtCode("废止",new Date(),"靓证废止失败，无有效返回",Long.parseLong(id));
                }
                continue;
            }
            log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.result：" + content);
            FileUtil.del(file);
            log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.删除文件：" + filename);
            try{
                json = JSONObject.parseObject(content);
                //失败处理
                if("FAILURE".equals(json.getString("ack_code"))){
                    String errJson = json.getString("errors");
                    JSONArray jsonArray = JSONArray.parseArray(errJson);
                    JSONObject errObj = (JSONObject)jsonArray.get(0);
                    String msg = errObj.getString("message");
                    if("01".equals(type)){
                        if(StringUtils.isNotEmpty(msg)&& (msg.contains("该电子证照不存在")|| msg.contains("文件不存在或内容为空"))){
                            signatureQueuesRepository.updateJtCode("",new Date(),"靓证废止失败:"+msg,Long.parseLong(id));
                        } else {
                            signatureQueuesRepository.updateJtCode("废止",new Date(),"靓证废止失败:"+msg,Long.parseLong(id));
                        }
                    }else if("15".equals(type)){
                        if(StringUtils.isNotEmpty(msg)&& (msg.contains("该电子证照不存在")|| msg.contains("文件不存在或内容为空"))){
                            signatureQueuesDocumentRepository.updateJtCode("",new Date(),"靓证废止失败:"+msg,Long.parseLong(id));
                        } else {
                            signatureQueuesDocumentRepository.updateJtCode("废止",new Date(),"靓证废止失败:"+msg,Long.parseLong(id));
                        }
                    }
                    continue;
                }else{
                    if("01".equals(type)){
                        signatureQueuesRepository.updateJtCode("",new Date(),"靓证废止成功:重新靓证",Long.parseLong(id));
                    }else if("15".equals(type)){
                        signatureQueuesDocumentRepository.updateJtCode("",new Date(),"靓证废止成功:重新靓证",Long.parseLong(id));
                    }
                }
                log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.success：end");
            } catch (Exception e){
                log.error("====> 解析靓证废止结果定时任务.updateJTLZFZ.fail：" + e.getMessage());
            }
        }
    }

    @Data
    public static class SignatureData {
        private String name;
        private String address;
        private String headphoto;
        private String idcardno;
        private String year;
        private String month;
        private String day;
        private String certificateno;
        private String certificatefrom;
        private String isSignature;
        //发证日期
        private String fzDate;
        private String zYear;
        private String zMonth;
        private String zDay;
        private String signatureImg;
        //未签章pdf存储路径
        private String unSignaturePDF;
        //已签章pdf扫描路径
        private String signaturePDF;
    }


    @Data
    public static class OperatorData {
        private String account;//账号
        private String name;
        private String idcardno;
        private String orgName;//机构名称
        private String roleName;//角色名称
        private String regionName;//归属区域
        private String regionCode;

        public static OperatorData fixedOperatorData(){
            OperatorData operatorData = new OperatorData();
            operatorData.setAccount("003849");
            operatorData.setName("王鑫");
            operatorData.setIdcardno("110104198412242026");
            operatorData.setOrgName("北京市治安管理总队");
            operatorData.setRoleName("二级警长");
            operatorData.setRegionName("西城区");
            operatorData.setRegionCode("110102");
            return operatorData;
        }
    }


    @Data
    public static class FileData {
        private String filename;//文件名
        private String filetype;//文件类型
        private String filebase64;//文件base64
        private String description;//说明

        public FileData(String filename, String filetype, String filebase64, String description){
            this.filename = filename;
            this.filetype = filetype;
            this.filebase64 = filebase64;
            this.description = description;
        }
    }
}
