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

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.backend.core.exceptions.SaasNofoundException;
import com.bcxin.backend.domain.configs.FileModeOutConfig;
import com.bcxin.backend.domain.enums.ComparisonDocumentType;
import com.bcxin.backend.domain.enums.DocumentType;
import com.bcxin.backend.domain.enums.ResetDocumentType;
import com.bcxin.backend.domain.models.SignatureQueuesDocument;
import com.bcxin.backend.domain.repositories.SignatureQueuesDocumentRepository;
import com.bcxin.backend.domain.signature.service.BeiJingInDocumentSignature;
import com.bcxin.backend.domain.utils.ftp.FtpUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
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.PageRequest;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
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.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class BeiJingInDocumentSignatureServiceImpl implements BeiJingInDocumentSignature {

    private final SignatureQueuesDocumentRepository signatureQueuesDocumentRepository;
    @Value("${myapps.domain.url}")
    String urlHead;
    @Value("${myapps.signature.unSignaturePDF}")
    String unSignatureSignatureToPDFServiceImplPDF;
    @Value("${myapps.signature.signaturePDF}")
    String signaturePDF;
    @Value("${myapps.signature.tempPDF}")
    String tempPDF;
    @Value("${myapps.signature.cgiApi}")
    String cgiApi;

    @Value("${myapps.storage.root}")
    String rootPath;

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

    //文书业务目录
    private static final String DOCUMENTPATH = "/document";

    public BeiJingInDocumentSignatureServiceImpl(SignatureQueuesDocumentRepository signatureQueuesDocumentRepository) {
        this.signatureQueuesDocumentRepository = signatureQueuesDocumentRepository;
    }

    @Override
    public void initDocumentSignature() {
        try {
            createDocumentSignature_old();
        } catch (Exception e) {
            log.error("========> initDocumentSignature.error", e);
        }
    }

    @Override
    public void useDocumentSignature() {
        //读取未签章文书数据逐个触发签章，并保存签章结果
        updateDocumentSignature_old();
    }

    private void createDocumentSignature_old() {
        DocumentType[] list = DocumentType.values();
        for (DocumentType documentType : list) {
            if (StringUtils.isEmpty(documentType.getSelectSql())) {
                continue;
            }
            List<DocumentFile> paranms = jdbcTemplate.query(documentType.getSelectSql(), new RowMapper<DocumentFile>() {
                @Override
                public DocumentFile mapRow(ResultSet rs, int rowNum) throws SQLException {
                    DocumentFile row = new DocumentFile();
                    row.setBusiness_id(rs.getString("business_id"));
                    row.setPath(rs.getString("path"));
                    return row;
                }
            });

            log.error("========> createDocumentSignature_old.paranms:", paranms);
            for (DocumentFile documentFile : paranms) {
                try {
                    String businessId = documentFile.getBusiness_id();
                    String path = getPath(documentFile.getPath());
                    if (StringUtils.isEmpty(path)) {
                        continue;
                    }

                    log.info("========> createDocumentSignature.path: {}; businessId={}; type={}", path, businessId, documentType.getValue());
                    SignatureQueuesDocument document =
                            signatureQueuesDocumentRepository.getSignatureQueuesDocument(businessId, documentType.getValue() + "");

                    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);

                        log.error("========> createDocumentSignature.save:{}", JSONObject.toJSONString(document));
                    } else {
                        //文书地址不一致重置记录重新签章靓证
                        if (!document.getFile_url().contains(path)) {
                            signatureQueuesDocumentRepository.resetDocumentPath(0, new Date(), path, "废止", document.getId());
                        }
                    }
                } catch (Exception ex) {
                    log.error("createDocumentSignature_old 处理签章事项; businessId={};path={}", documentFile.getBusiness_id(), documentFile.getPath(), ex);
                }
            }
        }
    }

    /**
     * <b> 查询所有应该产生文书签章记录但没有产生的数据，重新补录到文书签章表 </b>
     * @author ZXF
     * @create 2025/06/30 0030 14:20
     * @version
     * @注意事项 </b>
     */
    public void comparisonDocumentSignature() {
        ComparisonDocumentType[] list = ComparisonDocumentType.values();
        log.error("====> 北京内网检索所有遗漏的文书记录重新补录到文书签章表：每小时一次,ComparisonDocumentTypeSize:"+list.length+"................");
        for (ComparisonDocumentType documentType : list) {
            if (StringUtils.isEmpty(documentType.getSelectSql())) {
                continue;
            }
            List<DocumentFile> paranms = jdbcTemplate.query(documentType.getSelectSql(), new RowMapper<DocumentFile>() {
                @Override
                public DocumentFile mapRow(ResultSet rs, int rowNum) throws SQLException {
                    DocumentFile row = new DocumentFile();
                    row.setBusiness_id(rs.getString("business_id"));
                    row.setPath(rs.getString("path"));
                    return row;
                }
            });
            if(paranms.size()>0){
                log.error("========> comparisonDocumentSignature.SelectSql:", documentType.getSelectSql());
                log.error("========> comparisonDocumentSignature.params:", JSONArray.toJSONString(paranms));
            }
            for (DocumentFile documentFile : paranms) {
                try {
                    String businessId = documentFile.getBusiness_id();
                    String path = getPath(documentFile.getPath());
                    if (StringUtils.isEmpty(path)) {
                        continue;
                    }

                    log.error("========> comparisonDocumentSignature.path: {}; businessId={}; type={}", path, businessId, documentType.getName());
                    SignatureQueuesDocument document =
                            signatureQueuesDocumentRepository.getSignatureQueuesDocument(businessId, documentType.getValue() + "");

                    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);

                        log.error("========> comparisonDocumentSignature.save:{}", JSONObject.toJSONString(document));
                    } else {
                        //文书地址不一致重置记录重新签章靓证
                        if (!document.getFile_url().contains(path)) {
                            signatureQueuesDocumentRepository.resetDocumentPath(0, new Date(), path, "废止", document.getId());
                        }
                    }
                } catch (Exception ex) {
                    log.error("comparisonDocumentSignature 处理签章事项; businessId={};path={}", documentFile.getBusiness_id(), documentFile.getPath(), ex);
                }
            }
        }
    }

    private static 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) {
            log.error("无效的文书地址数据:path={}", path);
            return "";
        }
    }

    /**
     * <b> 查询正副本制证修改时间3分钟内，签章操作大于3分钟的，取文件地址配对，不匹配记录重置签章数据重新签章 </b>
     * @author ZXF
     * @create 2025/06/13 0013 15:08
     * @version
     * @注意事项 </b>
     */
    public void resetDocumentSignature() {
        ResetDocumentType[] list = ResetDocumentType.values();
        for (ResetDocumentType documentType:list) {
            if(StringUtils.isEmpty(documentType.getSelectSql())){
                continue;
            }
            List<DocumentFile> paranms = jdbcTemplate.query(documentType.getSelectSql(), new RowMapper<DocumentFile>() {
                @Override
                public DocumentFile mapRow(ResultSet rs, int rowNum) throws SQLException {
                    DocumentFile row = new DocumentFile();
                    row.setBusiness_id(rs.getString("business_id"));
                    row.setPath(rs.getString("path"));
                    return row;
                }});

            log.error("========> resetDocumentSignature.paranms:{}",JSONObject.toJSONString(paranms));
            for (DocumentFile documentFile: paranms) {
                try {
                    log.error("========> resetDocumentSignature.documentFile: {}", JSONObject.toJSONString(documentFile));

                    String businessId = documentFile.getBusiness_id();
                    String path = getPath(documentFile.getPath());
                    if (StringUtils.isEmpty(path)) {
                        continue;
                    }

                    log.error("resetDocumentSignature.path={};businessId={};type={}",path,businessId,documentType.getValue());
                    SignatureQueuesDocument document =
                            signatureQueuesDocumentRepository.getSignatureQueuesDocument(businessId, documentType.getValue() + "");
                    //文书地址不一致重置记录重新签章靓证
                    if (document != null && !document.getFile_url().contains(path)) {
                        signatureQueuesDocumentRepository.resetDocumentPath(0, new Date(), path, "废止", document.getId());
                    }
                } catch (Exception ex) {
                    log.error(
                            "异常处理-resetDocumentSignature：businessId={}; path={}",
                            documentFile.getBusiness_id(),
                            documentFile.getPath(), ex);
                }
            }
        }

    }

    /**
     * <b> 存在签章数据fileurl为null的情况通过该业务重置地址重新签章 </b>
     * @author ZXF
     * @create 2025/01/16 0016 17:42
     * @version
     * @注意事项 </b>
     */
    private void repairFileNull() {
        List<SignatureQueuesDocument>  queues = signatureQueuesDocumentRepository.queuesFileNull();
        DocumentType type;
        List<String> paranms;
        for (SignatureQueuesDocument queuesDocument:queues){
            try {
                type = DocumentType.getByValue(Integer.parseInt(queuesDocument.getBusiness_type()));
                String sql = "SELECT "+type.getFileField()+" AS 'fileUrl' FROM "+type.getTableName()+" WHERE ID='"+queuesDocument.getBusiness_id()+"';";
                paranms = jdbcTemplate.query(sql, new RowMapper<String>() {
                    @Override
                    public String mapRow(ResultSet rs, int rowNum) throws SQLException {
                        return rs.getString("fileUrl");
                    }});
                if(paranms.size()>0){
                    String fileUrl = paranms.get(0);
                    if(StringUtils.isEmpty(fileUrl)||"null".equals(fileUrl)){
                        throw new Exception("原数据文件异常");
                    }
                    signatureQueuesDocumentRepository.resetDocumentPath(0,new Date(),fileUrl,"",queuesDocument.getId());
                }
            }catch (Exception e){
                System.err.println("========> createDocumentSignature.repairFileNull.error: " + e.getMessage());
            }
        }
    }

    /**
     * <b> 文件签章并删除in/document、out/document目录下对应文件 </b>
     * @author ZXF
     * @create 2024/11/28 0028 15:09
     * @version
     * @注意事项 </b>
     */
    private boolean documentQuicklyServer(SignatureQueuesDocument document) {
        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);
            log.error("复制文件sourcePath={}; sourceInPath={}",sourcePath,sourceInPath);
        } catch (IOException e) {
            log.error("异常-复制文件(SignatureQueuesDocument.Id={})sourcePath={}; sourceInPath={}", document.getId(), sourcePath, sourceInPath, e);
            throw new SaasNofoundException("找不到原文件");
        }

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

        log.error("执行activateXMPDocumentQuicklyExCGI的结果: boo={}",boo);
        //3.判断返回结果，如果失败，删除/uploads/pdf/dianziqianzhang/in/document 目录下对应名称的文件，然后返回false，
        try {
            Files.delete(sourceInPath);
        } catch (IOException e) {
            log.error("删除(SignatureQueuesDocument.Id={})sourceInPath={} 发生异常", document.getId(), sourceInPath, e);
        }

        if(!boo){
            return boo;
        }

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

        //5.删除/uploads/pdf/dianziqianzhang/out/document 目录下对应名称的文件
        try {
            Files.delete(sourceOutPath);
        } catch (IOException e) {
            log.error("异常: 删除 (SignatureQueuesDocument.Id={})sourceOutPath={} 异常", document.getId(), sourceOutPath, e);
        }

        //6.然后返回true
        return boo;
    }

    /**
     * <b> 激活电子印章签验接口服务器完成签章 </b>
     * @author ZXF
     * @create 2022/11/21 0021 10:44
     * @version
     * @注意事项 </b>
     */
    private boolean activateXMPDocumentQuicklyExCGI(String stamp_xy) {
        StringBuilder sb = new StringBuilder();
        try {
            String[] arrXY = stamp_xy.split(",");
            JSONObject json = new JSONObject();
            json.put("service", "wss://127.0.0.1:8800");
            json.put("sn", "2171101001014060");//保安管理专用章 UKey编码
            json.put("pin", "88888888");
            json.put("in", "/data/share/in/document");
            json.put("out", "/data/share/out/document");
            JSONArray arr = new JSONArray();
            JSONObject pos = new JSONObject();
            pos.put("centerX", Integer.parseInt(arrXY[1]));
            pos.put("centerY", Integer.parseInt(arrXY[2]));
            pos.put("page", Integer.parseInt(arrXY[0]));
            arr.add(pos);
            json.put("signOnPos", arr);
            String ret = HttpUtil.post(cgiApi, json.toJSONString());
            sb.append(String.format("result=%s",ret));
            if (StringUtils.isEmpty(ret)) {
                return false;
            }
            JSONObject result = JSON.parseObject(ret.replace("#", ""));
            if ("1".equals(String.valueOf(result.get("code")))) {
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error("执行 activateXMPDocumentQuicklyExCGI: {} 发生异常", stamp_xy, e);
        }
        finally {
            log.error("执行 activateXMPDocumentQuicklyExCGI跟踪信息:{}", sb);
        }

        return false;
    }

    private void updateDocumentSignature_old(){
        //查询待签章的数据300条
        List<SignatureQueuesDocument> list = signatureQueuesDocumentRepository.pageQueues(0, PageRequest.of(0, 80)).getContent();
        for (SignatureQueuesDocument document: list) {
            try {
                boolean boo = documentQuicklyServer(document);
                if (boo) {
                    // 检查签章是否存在
                    boolean hasRedSeal = checkPdfForRedSeal(document.getFile_url());
                    if (!hasRedSeal) {
                        log.warn("文件 {} 中未检测到红色印章", document.getFile_url());
                        signatureQueuesDocumentRepository.updateSignatureQueuesDocument(0, new Date(), "文书未检测到印章：重置状态", document.getId());
                    } else {
                        signatureQueuesDocumentRepository.updateSignatureQueuesDocument(1, new Date(), "文书签章成功", "废止", document.getId());
                    }
                } else {
                    signatureQueuesDocumentRepository.updateSignatureQueuesDocument(2, new Date(), "文书签章失败", document.getId());
                }
            } catch (SaasNofoundException ex) {
                signatureQueuesDocumentRepository.updateSignatureQueuesDocument(2, new Date(), "404-" + ex.getMessage(), document.getId());
                log.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());
                log.error("updateDocumentSignature_old: document.id={}; status={}, fileUrl={}",
                        document.getId(), document.getStatus(), document.getFile_url(), ex);
            }
        }
    }

    // 添加最小印章像素阈值（例如：50x50 像素）
    private static final int MIN_SEAL_PIXELS = 50 * 50;

    /**
     * <b> 是否存在红章，当前阈值为2500（经多样例调试，印章像素值>=6144） </b>
     * @author ZXF
     * @create 2025/06/20 0020 14:37
     * @version
     * @注意事项 </b>
     */
    public boolean checkPdfForRedSeal(String filePath) {
        try {
            Path pdfPath = Paths.get(rootPath + filePath);
            File file = pdfPath.toFile();

            if (!file.exists()) {
                log.error("文件不存在: {}", filePath);
                return false;
            }

            try (PDDocument document = PDDocument.load(file)) {
                PDFRenderer pdfRenderer = new PDFRenderer(document);
                BufferedImage image = pdfRenderer.renderImageWithDPI(0, 300, ImageType.RGB);

                int width = image.getWidth();
                int height = image.getHeight();

                // 使用二维数组记录已访问的像素点
                boolean[][] visited = new boolean[height][width];
                int minSealDetected = 0;

                for (int y = 0; y < height; y++) {
                    for (int x = 0; x < width; x++) {
                        if (visited[y][x]) continue;

                        int rgb = image.getRGB(x, y);
                        int r = (rgb >> 16) & 0xFF;
                        int g = (rgb >> 8) & 0xFF;
                        int b = rgb & 0xFF;

                        // 判断是否为红色像素
                        if (r > 150 && g < 100 && b < 100) {
                            // 使用广度优先搜索查找连通区域
                            int areaSize = floodFill(image, x, y, visited, width, height);
                            if (areaSize > MIN_SEAL_PIXELS) {
                                log.info("发现疑似红色印章，面积：{}", areaSize);
                                minSealDetected++;
                            }
                        }
                    }
                }

                return minSealDetected > 0;

            } catch (IOException e) {
                log.error("读取PDF文件失败: {}", filePath, e);
            }
        } catch (Exception ex) {
            log.error("checkPdfForRedSeal: 执行失败:filePath={}", filePath, ex);
        }

        return false;
    }

    /**
     * 广度优先搜索计算红色连通区域大小
     */
    private static int floodFill(BufferedImage image, int startX, int startY, boolean[][] visited, int width, int height) {
        int count = 0;
        java.util.Queue<int[]> queue = new java.util.LinkedList<>();
        queue.add(new int[]{startX, startY});
        visited[startY][startX] = true;

        while (!queue.isEmpty()) {
            int[] point = queue.poll();
            int x = point[0];
            int y = point[1];

            count++;

            // 检查上下左右四个方向
            for (int dx = -1; dx <= 1; dx++) {
                for (int dy = -1; dy <= 1; dy++) {
                    if (dx == 0 && dy == 0) continue;
                    int nx = x + dx;
                    int ny = y + dy;

                    if (nx >= 0 && nx < width && ny >= 0 && ny < height && !visited[ny][nx]) {
                        int rgb = image.getRGB(nx, ny);
                        int r = (rgb >> 16) & 0xFF;
                        int g = (rgb >> 8) & 0xFF;
                        int b = rgb & 0xFF;

                        if (r > 150 && g < 100 && b < 100) {
                            visited[ny][nx] = true;
                            queue.add(new int[]{nx, ny});
                        }
                    }
                }
            }
        }

        return count;
    }

    public static void main(String[] args) {
        System.out.println(checkPdfForPortraitInTopLeft("\\Users\\Administrator\\Downloads\\C610700queueId_5150.pdf"));
    }

    /**
     * <b> 检测PDF文件第一页左上角是否存在头像（基于肤色像素比例） </b>
     * @param filePath 文件路径（相对于 rootPath）
     * @return 是否检测到头像
     */
    public static boolean checkPdfForPortraitInTopLeft(String filePath) {
        try {
            Path pdfPath = Paths.get("C:" + filePath);
//            Path pdfPath = Paths.get(rootPath + filePath);
            File file = pdfPath.toFile();

            if (!file.exists()) {
                log.error("文件不存在: {}", filePath);
                return false;
            }

            // 加载 PDF 文档
            try (PDDocument document = PDDocument.load(file)) {
                // 创建 PDF 渲染器以生成图像
                PDFRenderer renderer = new PDFRenderer(document);
                // 将第一页渲染为 300 DPI 的 RGB 图像
                BufferedImage image = renderer.renderImageWithDPI(0, 96, ImageType.RGB);

                int width = image.getWidth();
                int height = image.getHeight();

                // 定义左上角区域（25%宽 x 25%高）
                int roiX = 122; // 距离左边 0%
                int roiY = 69; // 距离顶部 0%
                int roiWidth = 109; // 宽度为 25%
                int roiHeight = 140; // 高度为 25%

                int skinPixelCount = 0;
                int totalPixelCount = roiWidth * roiHeight;

                // 遍历 ROI 区域的每个像素，统计肤色像素数量
                for (int y = roiY; y < roiY + roiHeight; y++) {
                    for (int x = roiX; x < roiX + roiWidth; x++) {
                        if (isEnhancedSkinColor(image, x, y, width, height)) {
                            skinPixelCount++;
                        }
                    }
                }

                // 计算肤色像素占比
                double skinRatio = (double) skinPixelCount / totalPixelCount;
                // 如果超过40%的像素为肤色，则认为存在头像
                boolean hasPortrait = skinRatio > 0.35;

                if (hasPortrait) {
                    log.info("在左上角发现疑似头像，肤色占比：{:.2f}%", skinRatio * 100);
                }

                return hasPortrait;
            } catch (IOException e) {
                log.error("读取PDF文件失败: {}", filePath, e);
            }
        } catch (Exception ex) {
            log.error("checkPdfForPortraitInTopRight 执行失败: filePath={}", filePath, ex);
        }

        return false;
    }

    private static boolean isEnhancedSkinColor(BufferedImage image, int x, int y, int width, int height) {
        int voteCount = 0;
        int total = 0;

        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                int nx = x + dx;
                int ny = y + dy;

                if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
                    int rgb = image.getRGB(nx, ny);
                    int r = (rgb >> 16) & 0xFF;
                    int g = (rgb >> 8) & 0xFF;
                    int b = rgb & 0xFF;

                    if (isSkinColorInYCbCr(r, g, b)) {
                        voteCount++;
                    }
                    total++;
                }
            }
        }

        return voteCount * 2 >= total;
    }

    private static boolean isSkinColorInYCbCr(int r, int g, int b) {
        double Y = 0.299 * r + 0.587 * g + 0.114 * b;
        double Cb = -0.1687 * r - 0.3313 * g + 0.5 * b + 128;
        double Cr = 0.5 * r - 0.4187 * g - 0.0813 * b + 128;

        return (Cb >= 77 && Cb <= 127 && Cr >= 133 && Cr <= 173);
    }

    /**
     * <b> 批量插入符合签章条件的文书记录 </b>
     * @author ZXF
     * @create 2022/10/31 0031 13:33
     * @version
     * @注意事项 </b>
     */
    private void createDocumentSignature() {
        String ftpIn = FileModeOutConfig.getFilePath();
        DocumentType[] list = DocumentType.values();
        for (DocumentType documentType:list) {
            if(StringUtils.isEmpty(documentType.getSelectSql())){
                continue;
            }
            System.err.println("========> documentType.getSelectSql(): " + documentType.getSelectSql());
            List<Map> paranms = new ArrayList<>();
            try {
                //TODO 这里selectsql查询内容需要改造包含：业务信息、操作人信息
                paranms = jdbcTemplate.query(documentType.getSelectSql(), BeanPropertyRowMapper.newInstance(Map.class));
            }catch (Exception e){
                System.err.println("========> createDocumentSignature.jdbcTemplate.query: " + e.getMessage());
            }
            for (Map map: paranms) {
                System.err.println("========> createDocumentSignature: " + map.toString());
                String businessId = (String) map.get("business_id");
                if(map.get("path")==null){
                    continue;
                }
                String path = (String) map.get("path");
                if(path.startsWith("[")){
                    path = path.replace("[","").replace("]","");
                    JSONObject json = JSONObject.parseObject(path);
                    path = json.getString("path");
                }
                if(StringUtils.isEmpty(path)){
                    continue;
                }
                String fileName = fileUUIDName(path);
                //文书文件上传ftp
                boolean boo = FtpUtil.uploadBase64(ftpIn, fileName, fileToBase64(rootPath + path));
                if(!boo){
                    continue;
                }
                //重新复制一份新的文件，用新文件去签章
                SignatureQueuesDocument document = signatureQueuesDocumentRepository.getSignatureQueuesDocument(businessId,documentType.getValue()+"");
                if(document != null){
                    continue;
                }
                document = new SignatureQueuesDocument();
                document.setCreated(new Date());
                document.setLastmodified(new Date());
                //保安服务许可证证书签章业务需要以下2个参数
                //TODO 操作人信息
//                document.setOperator();
                //TODO 业务信息
//                document.setData();
                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+"|"+fileName);//原存储文件路径 | ftp新文件路径
                // 其他必要的初始化操作
                signatureQueuesDocumentRepository.save(document);
                String documentContent = JSONObject.toJSONString(document);
                System.err.println("========> createDocumentSignature.document: " + documentContent);
                FtpUtil.uploadBase64(ftpIn, "IN|"+document.getBusiness_type()+"|"+businessId+".bcx", documentContent);
                System.err.println("========> createDocumentSignature.businessId: " + businessId+"，end----");
            }
        }

    }

    /**
     * <b> 获取新UUID文件名 </b>
     * @author ZXF
     * @create 2024/12/09 0009 15:09
     * @version
     * @注意事项 </b>
     */
    public static String fileUUIDName(String filePath) {
        Path path = Paths.get(filePath);
        String fileName = path.getFileName().toString();

        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex > 0 && lastDotIndex < fileName.length() - 1) {
            String fileExtension = UUID.randomUUID().toString()+"."+fileName.substring(lastDotIndex + 1);
            System.out.println("File UUID name: " + fileExtension);
            return fileExtension;
        }
        return "";
    }

    private static String fileToBase64(String filePath) {
        File file = new File(filePath);
        try (FileInputStream fis = new FileInputStream(file)) {
            // 读取文件内容
            byte[] bytes = IoUtil.readBytes(fis);
            // 转换为 Base64 字符串
            return Base64.encode(bytes);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * <b> 根据文件地址重新复制一份，返回新文件地址 </b>
     * @author ZXF
     * @create 2024/11/23 0023 16:13
     * @version
     * @注意事项 </b>
     */
    private static String copyFile(String originalFilePath,String rootPath) {

        try {
            // 将字符串路径转换为Path对象
            Path sourcePath = Paths.get(rootPath+originalFilePath);

            // 获取文件名和扩展名
            String fileName = sourcePath.getFileName().toString();
            String fileExtension = getFileExtension(fileName);

            // 生成新的文件名（UUID）
            String newFileName = UUID.randomUUID().toString() + "." + fileExtension;

            // 新文件路径
            Path targetPath = sourcePath.getParent().resolve(newFileName);

            // 使用Files.copy方法复制文件
            Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
            String newPath = targetPath.toString().replace(rootPath,"");
            System.out.println("文件复制成功！新文件路径: " + newPath);
            return newPath;
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("文件复制失败: " + e.getMessage());
        }
        return "";
    }

    // 获取文件扩展名的方法
    private static String getFileExtension(String fileName) {
        int lastIndexOfDot = fileName.lastIndexOf('.');
        if (lastIndexOfDot == -1) {
            return ""; // 没有扩展名
        }
        return fileName.substring(lastIndexOfDot + 1);
    }

    /**
     * <b> 文书签章结果确认 </b>
     * @author ZXF
     * @create 2024/11/27 0027 16:55
     * @version
     * @注意事项 </b>
     */
    private void updateDocumentSignature(){
        //ftp文件存储路径
//        String ftpOut = FileModeOutConfig.getFilePath()+FileModeOutConfig.getOutPath() + DOCUMENTPATH + "/" + DateUtil.today();
        String ftpOut = FileModeOutConfig.getFilePath();
        List<String> files = FtpUtil.filenames(ftpOut,"");// TODO 定义文件类型
        SignatureQueuesDocument document;
        for (String filename: files){
            log.error("====> 文书签章结果确认定时任务.updateDocumentSignature.filename：" + filename);
            String content = FtpUtil.getFileContent(ftpOut,filename);
            if(StringUtils.isEmpty(content)){
                continue;
            }
            document = JSON.parseObject(content, SignatureQueuesDocument.class);
            log.error("====> 文书签章结果确认定时任务.updateDocumentSignature.document：" + JSON.toJSONString(document));
            if(document == null){
                continue;
            }
            if("2".equals(document.getStatus())){
                signatureQueuesDocumentRepository.updateSignatureQueuesDocument(document.getStatus(),new Date(),document.getProcessed_result(),document.getId());
                log.error("====> 文书签章结果确认定时任务.updateDocumentSignature.fail：end");
                continue;
            }
            // 获取ftp文件内容重新写入原文件地址
            String[] arr = document.getFile_url().split("-");
            String baseeContent = FtpUtil.downloadAsBase64(ftpOut,arr[1]);
            boolean boo = base64ToFile(baseeContent, rootPath + arr[0]);
            //写入原文件后对数据记录不做修改动作
//            if(boo){
//                String updateSql = DocumentType.getByValue(Integer.parseInt(document.getBusiness_type())).getUpdateSql();
//                updateSql = String.format(updateSql,document.getFile_url(),document.getBusiness_id());
//                log.error("====> 文书签章结果确认定时任务.updateDocumentSignature.updateSql：" + updateSql);
//                jdbcTemplate.update(updateSql);
                log.error("====> 文书签章结果确认定时任务.updateDocumentSignature.success：end");
//            }
        }
    }

    public static boolean base64ToFile(String base64String, String filePath) {
        try {
            // 解码 Base64 字符串为字节数组
            byte[] bytes = Base64.decode(base64String);

            // 获取文件对象
            File file = FileUtil.file(filePath);

            // 创建文件输出流
            try (FileOutputStream fos = new FileOutputStream(file)) {
                // 写入字节数组到文件
                IoUtil.write(fos, true, bytes);
            }

            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    @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 isSignature;
        //发证日期
        private String fzDate;
        private String zYear;
        private String zMonth;
        private String zDay;
        private String signatureImg;
        //未签章pdf存储路径
        private String unSignaturePDF;
        //已签章pdf扫描路径
        private String signaturePDF;
    }

    /**
     * Restful 接口返回的资源对象
     *
     */
    @Data
    public static class Resource {
        private int errcode;
        private String errmsg;
        private Object data;
    }
    @Data
    public static class DocumentFile {
        private String business_id;
        private String path;
    }
}
