package com.czg.third.wechat;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.czg.dto.req.WechatNotifyReqDto;
import com.czg.exception.CzgException;
import com.czg.third.wechat.dto.config.WechatPayConfigDto;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.Signer;
import com.wechat.pay.java.core.util.NonceUtil;
import lombok.extern.slf4j.Slf4j;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 微信请求工具类
 *
 * @author yjjie
 * @date 2025/12/29 10:02
 */
@Slf4j
public class WechatReqUtils {

    public static String postReq(WechatPayConfigDto configDto, String url, String body) {
        return req(configDto, url, "POST", body);
    }

    public static String getReq(WechatPayConfigDto configDto, String url, Map<String, Object> params) {
        url = Arrays.stream(params.entrySet().toArray(new Map.Entry[0]))
                .map(entry -> entry.getKey() + "=" + URLEncoder.encode(entry.getValue().toString(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&", url + "?", ""));

        // 如果最后没有参数，则去掉多余的 "?"
        url = url.endsWith("?") ? url.substring(0, url.length() - 1) : url;

        return req(configDto, url, "GET", "");
    }

    private static String req(WechatPayConfigDto configDto, String url, String method, String body) {
        if (configDto == null) {
            configDto = WechatPayConfigDto.getDefaultConfig();
        }
        long timestamp = getTimestamp();
        String nonce = getNonceStr();
        String signature = encryptReqParam(configDto, method, url, body, timestamp, nonce);
        String authorization = String.format("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\",timestamp=\"%d\",serial_no=\"%s\"",
                configDto.getMerchantId(), nonce, signature, timestamp, configDto.getSerialNumber());

        HttpRequest request = switch (method) {
            case "POST" -> HttpUtil.createPost(configDto.getDomain() + url)
                    .header("Authorization", authorization)
                    .header("Wechatpay-Serial", configDto.getPublicKeyId())
                    .charset(StandardCharsets.UTF_8)
                    .contentType("application/json")
                    .body(body);

            case "GET" -> HttpUtil.createGet(configDto.getDomain() + url)
                    .header("Authorization", authorization)
                    .header("Wechatpay-Serial", configDto.getPublicKeyId())
                    .charset(StandardCharsets.UTF_8)
                    .contentType("application/json");
            default -> throw new CzgException("不支持的请求方法");
        };
        log.info("微信支付请求：url = {}  \nauthorization: {}", request.getUrl(), authorization);
        HttpResponse response = request.execute();
        String s = response.body();
        log.info("微信支付请求：\n\turl = {}\n\tmethod: {}\n\tbody: {}\n\tresp: {}", url, method, body, s);
        return s;
    }

    /**
     * 加密请求参数
     *
     * @param configDto 配置
     * @param method    请求方法
     * @param url       请求地址
     * @param body      请求报文主体
     * @return 加密后的报文
     * <p>
     * 签名方法
     * HTTP请求方法\n
     * URL\n
     * 请求时间戳\n
     * 请求随机串\n
     * 请求报文主体\n
     */
    public static String encryptReqParam(WechatPayConfigDto configDto, String method, String url, String body, long timestamp, String nonce) {
        String encryptStr = String.format("%s\n%s\n%d\n%s\n%s\n",
                method, url, timestamp, nonce, body);

        Config config = WechatConfig.getRsaConfig(configDto);
        Signer signer = config.createSigner();
        String signature = signer.sign(encryptStr).getSign();
        log.info("微信签名 encryptStr = \n{}  \nsignature：{}", encryptStr, signature);
        return signature;
    }

    /**
     * 解密微信回调报文
     *
     * @param configDto 配置
     * @param reqDto    请求报文
     * @return 解密后的报文
     */
    public static String decryptRespParam(WechatPayConfigDto configDto, WechatNotifyReqDto reqDto) {
        if (configDto == null) {
            configDto = WechatPayConfigDto.getDefaultConfig();
        }
        WechatAesUtil aesUtil = new WechatAesUtil(configDto.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        try {
            return aesUtil.decryptToString(
                    reqDto.getResource().getAssociatedData() == null ? new byte[0] : reqDto.getResource().getAssociatedData().getBytes(StandardCharsets.UTF_8),
                    reqDto.getResource().getNonce().getBytes(StandardCharsets.UTF_8), reqDto.getResource().getCiphertext());
        } catch (Exception e) {
            log.error("【微信支付回调】解密失败 {}", reqDto);
            throw new CzgException("解密失败");
        }
    }

    /**
     * 获取随机串
     */
    private static String getNonceStr() {
        return NonceUtil.createNonce(32);
    }

    /**
     * 获取时间戳
     */
    private static long getTimestamp() {
        return System.currentTimeMillis() / 1000;
    }
}
