package com.gxwebsoft.common.core.utils;

import com.gxwebsoft.common.core.config.CertificateProperties;
import com.gxwebsoft.common.system.entity.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;


/**
 * 微信支付证书诊断工具
 * 专门用于诊断和解决证书相关问题
 *
 * @author 科技小王子
 * @since 2025-07-29
 */
@Slf4j
@Component
public class WechatPayCertificateDiagnostic {

    private final CertificateProperties certConfig;
    private final CertificateLoader certificateLoader;

    public WechatPayCertificateDiagnostic(CertificateProperties certConfig, CertificateLoader certificateLoader) {
        this.certConfig = certConfig;
        this.certificateLoader = certificateLoader;
    }

    /**
     * 全面诊断微信支付证书配置
     *
     * @param payment 支付配置
     * @param tenantId 租户ID
     * @param environment 环境（dev/prod）
     * @return 诊断结果
     */
    public DiagnosticResult diagnoseCertificateConfig(Payment payment, Integer tenantId, String environment) {
        DiagnosticResult result = new DiagnosticResult();

        log.info("=== 开始微信支付证书诊断 ===");
        log.info("租户ID: {}, 环境: {}", tenantId, environment);

        try {
            // 1. 检查基本配置
            checkBasicConfig(payment, result);

            // 2. 检查证书文件
            checkCertificateFiles(payment, tenantId, environment, result);

            // 3. 检查证书内容
            validateCertificateContent(payment, tenantId, environment, result);

            // 4. 生成建议
            generateRecommendations(result);

        } catch (Exception e) {
            result.addError("诊断过程中发生异常: " + e.getMessage());
            log.error("证书诊断异常", e);
        }

        log.info("=== 证书诊断完成 ===");
        return result;
    }

    /**
     * 检查基本配置
     */
    private void checkBasicConfig(Payment payment, DiagnosticResult result) {
        if (payment == null) {
            result.addError("支付配置为空");
            return;
        }

        if (payment.getMchId() == null || payment.getMchId().trim().isEmpty()) {
            result.addError("商户号未配置");
        } else {
            result.addInfo("商户号: " + payment.getMchId());
        }

        if (payment.getAppId() == null || payment.getAppId().trim().isEmpty()) {
            result.addError("应用ID未配置");
        } else {
            result.addInfo("应用ID: " + payment.getAppId());
        }

        if (payment.getMerchantSerialNumber() == null || payment.getMerchantSerialNumber().trim().isEmpty()) {
            result.addError("商户证书序列号未配置");
        } else {
            result.addInfo("商户证书序列号: " + payment.getMerchantSerialNumber());
        }

        if (payment.getApiKey() == null || payment.getApiKey().trim().isEmpty()) {
            result.addWarning("数据库中APIv3密钥未配置，将使用配置文件默认值");
        } else {
            result.addInfo("APIv3密钥: 已配置(" + payment.getApiKey().length() + "位)");
        }
    }

    /**
     * 检查证书文件
     */
    private void checkCertificateFiles(Payment payment, Integer tenantId, String environment, DiagnosticResult result) {
        if ("dev".equals(environment)) {
            // 开发环境证书检查
            String tenantCertPath = "dev/wechat/" + tenantId;
            String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
            String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile();

            // 检查私钥文件
            if (certificateLoader.certificateExists(privateKeyPath)) {
                result.addInfo("✅ 私钥文件存在: " + privateKeyPath);
                try {
                    String privateKeyFile = certificateLoader.loadCertificatePath(privateKeyPath);
                    result.addInfo("私钥文件路径: " + privateKeyFile);
                } catch (Exception e) {
                    result.addError("私钥文件加载失败: " + e.getMessage());
                }
            } else {
                result.addError("❌ 私钥文件不存在: " + privateKeyPath);
            }

            // 检查商户证书文件
            if (certificateLoader.certificateExists(apiclientCertPath)) {
                result.addInfo("✅ 商户证书文件存在: " + apiclientCertPath);
            } else {
                result.addWarning("⚠️ 商户证书文件不存在: " + apiclientCertPath + " (自动证书配置不需要此文件)");
            }

        } else {
            // 生产环境证书检查
            if (payment.getApiclientKey() != null) {
                result.addInfo("私钥文件配置: " + payment.getApiclientKey());
            } else {
                result.addError("生产环境私钥文件路径未配置");
            }

            if (payment.getApiclientCert() != null) {
                result.addInfo("商户证书文件配置: " + payment.getApiclientCert());
            } else {
                result.addWarning("生产环境商户证书文件路径未配置 (自动证书配置不需要此文件)");
            }
        }
    }

    /**
     * 验证证书内容
     */
    private void validateCertificateContent(Payment payment, Integer tenantId, String environment, DiagnosticResult result) {
        try {
            if ("dev".equals(environment)) {
                String tenantCertPath = "dev/wechat/" + tenantId;
                String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile();

                if (certificateLoader.certificateExists(apiclientCertPath)) {
                    validateX509Certificate(apiclientCertPath, payment.getMerchantSerialNumber(), result);
                }
            }
        } catch (Exception e) {
            result.addWarning("证书内容验证失败: " + e.getMessage());
        }
    }

    /**
     * 验证X509证书
     */
    private void validateX509Certificate(String certPath, String expectedSerialNumber, DiagnosticResult result) {
        try {
            String actualCertPath = certificateLoader.loadCertificatePath(certPath);

            try (InputStream inputStream = new FileInputStream(new File(actualCertPath))) {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);

                if (cert != null) {
                    String actualSerialNumber = cert.getSerialNumber().toString(16).toUpperCase();
                    result.addInfo("证书序列号: " + actualSerialNumber);
                    result.addInfo("证书有效期: " + cert.getNotBefore() + " 至 " + cert.getNotAfter());
                    result.addInfo("证书主体: " + cert.getSubjectX500Principal().toString());

                    // 检查序列号是否匹配
                    if (expectedSerialNumber != null && !expectedSerialNumber.equalsIgnoreCase(actualSerialNumber)) {
                        result.addError("证书序列号不匹配! 配置: " + expectedSerialNumber + ", 实际: " + actualSerialNumber);
                    } else {
                        result.addInfo("✅ 证书序列号匹配");
                    }

                    // 检查证书是否过期
                    long now = System.currentTimeMillis();
                    if (now < cert.getNotBefore().getTime()) {
                        result.addError("证书尚未生效");
                    } else if (now > cert.getNotAfter().getTime()) {
                        result.addError("证书已过期");
                    } else {
                        result.addInfo("✅ 证书在有效期内");
                    }
                } else {
                    result.addError("无法解析证书文件");
                }
            }
        } catch (Exception e) {
            result.addError("证书验证失败: " + e.getMessage());
        }
    }

    /**
     * 生成建议
     */
    private void generateRecommendations(DiagnosticResult result) {
        if (result.hasErrors()) {
            result.addRecommendation("🔧 修复建议:");

            String errorText = result.getErrors();
            if (errorText.contains("商户号")) {
                result.addRecommendation("1. 请在支付配置中设置正确的商户号");
            }

            if (errorText.contains("序列号")) {
                result.addRecommendation("2. 请检查商户证书序列号是否正确，可在微信商户平台查看");
            }

            if (errorText.contains("证书文件")) {
                result.addRecommendation("3. 请确保证书文件已正确放置在指定目录");
            }

            if (errorText.contains("过期")) {
                result.addRecommendation("4. 请更新过期的证书文件");
            }

            result.addRecommendation("5. 建议使用RSAAutoCertificateConfig自动证书配置，可避免手动管理证书");
            result.addRecommendation("6. 确保在微信商户平台开启API安全功能并申请使用微信支付公钥");
        } else {
            result.addRecommendation("✅ 证书配置正常，建议使用自动证书配置以获得最佳体验");
        }
    }

    /**
     * 诊断结果类
     */
    public static class DiagnosticResult {
        private final StringBuilder errors = new StringBuilder();
        private final StringBuilder warnings = new StringBuilder();
        private final StringBuilder info = new StringBuilder();
        private final StringBuilder recommendations = new StringBuilder();

        public void addError(String error) {
            if (errors.length() > 0) errors.append("\n");
            errors.append(error);
        }

        public void addWarning(String warning) {
            if (warnings.length() > 0) warnings.append("\n");
            warnings.append(warning);
        }

        public void addInfo(String information) {
            if (info.length() > 0) info.append("\n");
            info.append(information);
        }

        public void addRecommendation(String recommendation) {
            if (recommendations.length() > 0) recommendations.append("\n");
            recommendations.append(recommendation);
        }

        public boolean hasErrors() {
            return errors.length() > 0;
        }

        public String getErrors() {
            return errors.toString();
        }

        public String getWarnings() {
            return warnings.toString();
        }

        public String getInfo() {
            return info.toString();
        }

        public String getRecommendations() {
            return recommendations.toString();
        }

        public String getFullReport() {
            StringBuilder report = new StringBuilder();
            report.append("=== 微信支付证书诊断报告 ===\n\n");

            if (info.length() > 0) {
                report.append("📋 基本信息:\n").append(info).append("\n\n");
            }

            if (warnings.length() > 0) {
                report.append("⚠️ 警告:\n").append(warnings).append("\n\n");
            }

            if (errors.length() > 0) {
                report.append("❌ 错误:\n").append(errors).append("\n\n");
            }

            if (recommendations.length() > 0) {
                report.append("💡 建议:\n").append(recommendations).append("\n\n");
            }

            report.append("=== 诊断报告结束 ===");
            return report.toString();
        }
    }
}
