package org.dromara.zhishu.util;


import com.alibaba.fastjson.JSONObject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import jakarta.servlet.http.HttpServletRequest;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

public final class WxPayUtil {

    /**
     * 商户号
     */
    private static String MERCHANT_ID = "1524946931";
    /**
     * 商户API私钥路径
     */
//    private static String PRIVATE_KEY_PATH = "C:\\Users\\www\\erp1\\wxPay\\apiclient_key.pem";
    private static String PRIVATE_KEY_PATH = "/wxPay/apiclient_key.pem";
    /**
     * 商户证书序列号
     */
    private static String MERCHANT_SERIAL_NUMBER = "1FD5B441796BE0250622018DF43EC4BAFB34FB78";
    /**
     * 商户APIV3密钥
     */
    private static String APIV3KEY = "wjshUHNCGJKO1239874HSJKL8Q52F3G1";

    // 使用自动更新平台证书的RSA配置
    // 建议将 config 作为单例或全局静态对象，避免重复的下载浪费系统资源
    private static Config config =
            new RSAAutoCertificateConfig.Builder()
                    .merchantId(MERCHANT_ID)
                    .privateKeyFromPath(PRIVATE_KEY_PATH)
                    .merchantSerialNumber(MERCHANT_SERIAL_NUMBER)
                    .apiV3Key(APIV3KEY)
                    .build();

    public static String getApiV3Key() {
        return APIV3KEY;
    }

    /**
     * 调用微信支付接口
     *
     * @param taskId   充值任务id
     * @param total    计算后带手续费的金额
     * @param totalStr 充值金额
     * @return
     */
    public static String wxPay(Long taskId, Integer total, String totalStr, String orderId, String userId) {
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // JsapiService service = new JsapiService.Builder().config(config).build();
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(total);
        request.setAmount(amount);
        request.setAppid("wxec160b6872dc24cf");
        request.setMchid("1524946931");
        request.setDescription("充值金额:" + totalStr);
         request.setNotifyUrl("https://api.buzhiyushu.cn/weChat/wxPayCallBack");
//        request.setNotifyUrl("https://test.api.buzhiyushu.cn/weChat/wxPayCallBack");
        request.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
        JSONObject attach = new JSONObject();
        attach.put("taskId", taskId);
        attach.put("orderId", orderId);
        attach.put("userId", userId);
        request.setAttach(attach.toJSONString());
        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        return response.getCodeUrl();
    }

    public static String wxPay(Long taskId, Integer total, String totalStr) {
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        // JsapiService service = new JsapiService.Builder().config(config).build();
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(total);
        request.setAmount(amount);
        request.setAppid("wxec160b6872dc24cf");
        request.setMchid("1524946931");
        request.setDescription("充值金额:" + totalStr);
        request.setNotifyUrl("https://api.buzhiyushu.cn/weChat/wxPayCallBack2");
//        request.setNotifyUrl("https://test.api.buzhiyushu.cn/weChat/wxPayCallBack");
        request.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
        request.setAttach(taskId + "");
        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        return response.getCodeUrl();
    }


    /**
     * 调用微信支付接口
     *
     * @param taskId   充值任务id
     * @param total    计算后带手续费的金额
     * @param totalStr 充值金额
     * @return
     */
    public static String xcxPay(Long taskId, Integer total, String totalStr, String openid, String appid,String outTradeNo) {
        // 构建service
        JsapiService service = new JsapiService.Builder().config(config).build();
        // 使用jsapi包中的请求和金额模型
        com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest request =
                new com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest();
        com.wechat.pay.java.service.payments.jsapi.model.Amount amount =
                new com.wechat.pay.java.service.payments.jsapi.model.Amount();

        amount.setTotal(total);
        request.setAmount(amount);
        request.setOutTradeNo(outTradeNo);
        request.setAppid(appid); // 使用传入的appid
        request.setMchid("1524946931");
        request.setDescription("充值金额:" + totalStr);
        request.setNotifyUrl("https://api.buzhiyushu.cn/weChat/wxPayCallBack");
//        request.setOutTradeNo(UUID.randomUUID().toString().replace("-", ""));
        request.setAttach(taskId + "");
//        System.out.println("微信支付使用的订单号: " + outTradeNo);
        // 设置支付者信息 - JSAPI支付必须设置
        // 设置支付者（JSAPI必须）
        Payer payer = new Payer();
        payer.setOpenid(openid);
        request.setPayer(payer);

        // 调用下单方法，得到应答
        com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse response = service.prepay(request);

        // JSAPI支付返回的是prepay_id
        return response.getPrepayId();
    }

    /**
     * 生成微信支付API签名
     */
    public static String generateSignature(String body, String path) throws Exception {
        String method = "POST";
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonce = UUID.randomUUID().toString().replace("-", "");

        // 构建签名字符串
        String signString = method + "\n" + path + "\n" + timestamp + "\n" + nonce + "\n" + body + "\n";

        // 使用商户私钥签名
        PrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PATH);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(signString.getBytes(StandardCharsets.UTF_8));

        String sign = Base64.getEncoder().encodeToString(signature.sign());

        // 构建Authorization头
        return "mchid=\"" + MERCHANT_ID + "\",nonce_str=\"" + nonce + "\",timestamp=\"" + timestamp +
                "\",serial_no=\"" + MERCHANT_SERIAL_NUMBER + "\",signature=\"" + sign + "\"";
    }

    /**
     * xcx生成微信支付API签名
     */
    public static String xcxGenerateSignature(String body, String path, String httpMethod) throws Exception {
        // 修复1：动态传入HTTP方法
        String method = httpMethod;
        // 修复2：使用秒级时间戳
        String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        String nonce = UUID.randomUUID().toString().replace("-", "");

        // 修复3：处理URL参数排序
        URI uri = new URI("https://api.mch.weixin.qq.com" + path);
        String query = uri.getQuery();
        if (query != null) {
            // 对查询参数按字典序排序
            String sortedQuery = Arrays.stream(query.split("&"))
                    .sorted()
                    .collect(Collectors.joining("&"));
            path = uri.getPath() + "?" + sortedQuery;
        } else {
            path = uri.getPath();
        }

        // 修复4：正确构建签名串（GET请求末尾需两个换行符）
        String signString = method + "\n" +
                path + "\n" +
                timestamp + "\n" +
                nonce + "\n" +
                (body == null ? "" : body) + "\n"; // 关键：GET请求时body为空，但需保留末尾空行

        // 使用商户私钥签名
        PrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PATH);
        Signature signer = Signature.getInstance("SHA256withRSA");
        signer.initSign(privateKey);
        signer.update(signString.getBytes(StandardCharsets.UTF_8));

        String signature = Base64.getEncoder().encodeToString(signer.sign());

        // 构建Authorization头
        return "mchid=\"" + MERCHANT_ID + "\"," +
                "nonce_str=\"" + nonce + "\"," +
                "timestamp=\"" + timestamp + "\"," +
                "serial_no=\"" + MERCHANT_SERIAL_NUMBER + "\"," +
                "signature=\"" + signature + "\"";
    }

    /**
     * 生成小程序调起支付的签名
     */
    public static String generatePaySign(String signString) throws Exception {
        // 使用商户私钥签名
        PrivateKey privateKey = loadPrivateKeyFromPem(PRIVATE_KEY_PATH);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(signString.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(signature.sign());
    }

    /**
     * 从PEM文件加载私钥
     */
    public static PrivateKey loadPrivateKeyFromPem(String pemFilePath) throws Exception {
        // 读取PEM文件内容
        String pemContent = new String(Files.readAllBytes(Path.of(pemFilePath)), StandardCharsets.UTF_8);

        // 提取BASE64编码的私钥部分
        String privateKeyPEM = pemContent
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s", "");

        byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);

        // 创建PKCS8EncodedKeySpec
        java.security.spec.PKCS8EncodedKeySpec keySpec = new java.security.spec.PKCS8EncodedKeySpec(encoded);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");

        return keyFactory.generatePrivate(keySpec);
    }

    // Java后端生成二维码示例
    public static String generateQRCode(String url) {
        try {
            QRCodeWriter writer = new QRCodeWriter();
            BitMatrix matrix = writer.encode(url, BarcodeFormat.QR_CODE, 300, 300);

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(matrix, "PNG", out);

            // 将二维码图片转换为Base64字符串
            return Base64.getEncoder().encodeToString(out.toByteArray());
        } catch (Exception e) {
            throw new RuntimeException("生成二维码失败", e);
        }
    }

    // 获取请求头
    public static Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();
            headers.put(headerName.toLowerCase(), request.getHeader(headerName));
        }
        return headers;
    }

    // 获取请求体
    public static String getRequestBody(HttpServletRequest request) throws Exception {
        StringBuilder sb = new StringBuilder();
        String line;
        try (var reader = request.getReader()) {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
        }
        System.out.println("请求体：" + sb);
        return sb.toString();
    }

    // 获取请求体 返回Map<String, Object>
    public static Map<String, Object> getRequestBodyAsMap(HttpServletRequest request) throws IOException {
        // 读取请求体
        StringBuilder requestBody = new StringBuilder();
        try (BufferedReader reader = request.getReader()) {
            String line;
            while ((line = reader.readLine()) != null) {
                requestBody.append(line);
            }
        }
        // 将请求体解析为 JSON 对象
        JSONObject jsonObject = JSONObject.parseObject(requestBody.toString());
//        System.out.println("方法体转为map前的字符串" + JSONObject.parseObject(requestBody.toString()));
        // 将 JSON 对象转换为 Map
        return jsonObject.getInnerMap();
    }

    /**
     * AES-GCM 解密
     *
     * @param ciphertext     Base64编码的密文
     * @param nonce          随机数（Base64编码）
     * @param associatedData 关联数据
     * @param aesKey         APIv3密钥
     * @return 解密后的明文
     */
    public static String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext, byte[] aesKey)
            throws GeneralSecurityException, IOException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            SecretKeySpec key = new SecretKeySpec(aesKey, "AES");
            GCMParameterSpec spec = new GCMParameterSpec(128, nonce);
            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);
            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 从PEM文件加载公钥
     *
     * @param pemFilePath PEM文件路径
     * @return 公钥对象
     */
    public static PublicKey loadPublicKeyFromPem(String pemFilePath) throws Exception {
        // 读取PEM文件内容
        String pemContent = new String(Files.readAllBytes(Path.of(pemFilePath)), StandardCharsets.UTF_8);

        // 提取BASE64编码的公钥部分
        String publicKeyPEM = pemContent
                .replace("-----BEGIN CERTIFICATE-----", "")
                .replace("-----END CERTIFICATE-----", "")
                .replaceAll("\\s", "");

        byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);

        // 创建X509证书工厂
        CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
        X509Certificate certificate = (X509Certificate) certFactory.generateCertificate(
                new java.io.ByteArrayInputStream(encoded));

        return certificate.getPublicKey();
    }


    /**
     * 验证微信支付回调签名
     *
     * @param publicKey 微信支付平台公钥
     * @param body      回调请求体
     * @param signature 微信支付签名
     * @param timestamp 时间戳
     * @param nonce     随机串
     * @return 验证结果
     */
    public static boolean verifyWechatPaySignature(
            PublicKey publicKey,
            String body,
            String signature,
            String timestamp,
            String nonce) throws Exception {

        // 构造签名字符串
        String message = buildSignMessage(timestamp, nonce, body);

        // 验证签名
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initVerify(publicKey);
        sign.update(message.getBytes("UTF-8"));

        return sign.verify(Base64.getDecoder().decode(signature));
    }

    /**
     * 构造微信支付签名字符串
     */
    private static String buildSignMessage(String timestamp, String nonce, String body) {
        return timestamp + "\n" + nonce + "\n" + body + "\n";
    }
}
