package com.seer.teach.pay.app.util;

import com.seer.teach.common.utils.AESUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.HashSet;
import java.util.Set;

/**
 * 配置解密工具类
 * 用于安全地解密配置参数，避免对未加密数据进行解密操作
 */
@Slf4j
@Component
public class ConfigDecryptUtil {
    
    // 已知的微信支付配置参数特征，用于判断是否可能是加密数据
    private static final Set<String> KNOWN_PLAINTEXT_PATTERNS = new HashSet<>();
    
    static {
        // 微信支付常见的明文参数特征
        KNOWN_PLAINTEXT_PATTERNS.add("wx"); // appId通常以wx开头
        KNOWN_PLAINTEXT_PATTERNS.add("1602476639"); // 示例商户号
        KNOWN_PLAINTEXT_PATTERNS.add("-----BEGIN"); // PEM证书格式开头
        KNOWN_PLAINTEXT_PATTERNS.add("PUB_KEY_ID"); // 公钥ID特征
    }

    /**
     * 安全解密配置参数
     * 先判断数据是否可能是加密数据，再进行解密操作
     * @param encryptedValue 可能的加密值
     * @return 解密后的值，如果解密失败或不是加密数据则返回原始值
     */
    public static String safeDecrypt(String encryptedValue) {
        return safeDecrypt(encryptedValue, false);
    }
    
    /**
     * 安全解密配置参数（支持PEM格式特殊处理）
     * @param encryptedValue 可能的加密值
     * @param isPem 是否是PEM格式证书
     * @return 解密后的值，如果解密失败或不是加密数据则返回原始值
     */
    public static String safeDecrypt(String encryptedValue, boolean isPem) {
        if (!StringUtils.hasText(encryptedValue)) {
            return encryptedValue;
        }

        // 判断是否可能是加密数据
        if (!isPossiblyEncrypted(encryptedValue, isPem)) {
            log.debug("数据不像是加密数据，跳过解密: {}", encryptedValue);
            return encryptedValue;
        }

        try {
            // 尝试解密
            String decryptedValue = AESUtils.decrypt(encryptedValue);
            if (decryptedValue != null && !decryptedValue.isEmpty()) {
                log.debug("数据解密成功");
                log.debug("解密前数据长度: {}, 解密后数据长度: {}", encryptedValue.length(), decryptedValue.length());
                // 如果是PEM格式，进行特殊处理
                if (isPem) {
                    log.debug("PEM格式数据，进行特殊处理");
                    decryptedValue = processPemContent(decryptedValue);
                    log.debug("PEM格式数据处理后长度: {}", decryptedValue.length());
                }
                return decryptedValue;
            } else {
                log.warn("解密返回空值，使用原始值");
                return encryptedValue;
            }
        } catch (Exception e) {
            log.warn("解密失败，使用原始值: {}", e.getMessage());
            return encryptedValue;
        }
    }

    /**
     * 判断数据是否可能是加密数据
     * 通过检查数据特征来判断
     * @param value 待检查的值
     * @param isPem 是否是PEM格式
     * @return 是否可能是加密数据
     */
    private static boolean isPossiblyEncrypted(String value, boolean isPem) {
        try {
            // 如果是PEM格式且包含PEM特征，直接认为是明文
            if (isPem && value.contains("-----BEGIN")) {
                log.debug("PEM数据包含明文特征，跳过解密");
                return false;
            }
            
            // 检查是否是已知的明文特征
            for (String pattern : KNOWN_PLAINTEXT_PATTERNS) {
                // 对于非PEM数据，检查明文特征
                if (!isPem && value.contains(pattern)) {
                    log.debug("数据包含明文特征，跳过解密: {}", pattern);
                    return false;
                }
            }
            
            // 检查长度特征，加密数据通常比明文长
            if (value.length() < 20) {
                log.debug("数据长度较短，可能是明文: {}", value);
                return false;
            }

            // 检查是否包含URL编码特征
            if (!value.contains("%")) {
                // 检查是否包含Base64特征
                if (!value.matches("^[A-Za-z0-9+/=]+$")) {
                    log.debug("数据不符合Base64编码特征");
                    return false;
                }
            }

            // 如果能通过基本检查，认为可能是加密数据
            log.debug("数据可能是加密的，将尝试解密");
            return true;
        } catch (Exception e) {
            log.debug("数据格式检查异常: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 处理PEM格式内容，确保格式正确
     * @param pemContent PEM内容
     * @return 处理后的PEM内容
     */
    private static String processPemContent(String pemContent) {
        try {
            log.debug("开始处理PEM内容，原始长度: {}", pemContent.length());
            
            // 移除可能的非法字符
            pemContent = pemContent.replace("\\n", "\n")
                                  .replace("\\r", "\r")
                                  .replace("\\t", "\t")
                                  .replace("\\", ""); // 移除所有反斜杠
            
            // 移除多余的空白字符，但保留必要的换行符
            pemContent = pemContent.replaceAll("[ \\t]+", " ")  // 将多个空格或制表符替换为单个空格
                                  .replace(" ", "")
                                  .trim();
            
            // 确保BEGIN和END标记格式正确（包含正确的空格）
            pemContent = pemContent.replace("-----BEGINPRIVATEKEY-----", "-----BEGIN PRIVATE KEY-----")
                                  .replace("-----ENDPRIVATEKEY-----", "-----END PRIVATE KEY-----")
                                  .replace("-----BEGINPUBLICKEY-----", "-----BEGIN PUBLIC KEY-----")
                                  .replace("-----ENDPUBLICKEY-----", "-----END PUBLIC KEY-----");
            
            // 确保PEM格式正确
            if (pemContent.contains("-----BEGIN")) {
                log.debug("PEM内容需要格式化");
                pemContent = formatPemContent(pemContent);
            }
            
            log.debug("PEM内容处理完成，处理后长度: {}", pemContent.length());
            return pemContent;
        } catch (Exception e) {
            log.warn("PEM内容处理异常: {}", e.getMessage());
            return pemContent;
        }
    }
    
    /**
     * 格式化PEM内容，确保每64个字符后有换行符
     * @param pemContent PEM内容
     * @return 格式化后的PEM内容
     */
    private static String formatPemContent(String pemContent) {
        try {
            // 确定是私钥还是公钥
            String beginMarker = "-----BEGIN PRIVATE KEY-----";
            String endMarker = "-----END PRIVATE KEY-----";
            boolean isPrivateKey = pemContent.contains(beginMarker);
            
            if (!isPrivateKey) {
                beginMarker = "-----BEGIN PUBLIC KEY-----";
                endMarker = "-----END PUBLIC KEY-----";
            }
            
            // 如果不包含BEGIN标记，说明可能不是完整的PEM格式
            if (!pemContent.contains(beginMarker)) {
                log.warn("PEM内容不包含BEGIN标记，返回原始内容");
                return pemContent;
            }
            
            // 提取核心内容（移除BEGIN和END标记以及所有换行符和空格）
            String coreContent = pemContent.replace(beginMarker, "")
                                          .replace(endMarker, "")
                                          .replaceAll("[\\s\\r\\n]+", "")  // 移除所有空白字符
                                          .trim();
            
            // 每64个字符添加换行符
            StringBuilder formatted = new StringBuilder();
            formatted.append(beginMarker).append("\n");
            
            for (int i = 0; i < coreContent.length(); i += 64) {
                int end = Math.min(i + 64, coreContent.length());
                formatted.append(coreContent.substring(i, end)).append("\n");
            }
            
            formatted.append(endMarker).append("\n");
            
            log.debug("PEM内容格式化完成");
            return formatted.toString();
        } catch (Exception e) {
            log.warn("PEM内容格式化异常: {}", e.getMessage());
            return pemContent;
        }
    }
}