package com.ruoyi.app.utils.newebpay;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 蓝新金流(NewebPay) HTTP 客户端。
 *
 * <p>对应官方手册 NDNF-1.2.2：
 * <ul>
 *   <li>{@link #createMpgForm} — MPG 幕前支付：组装加密 form 字段，前端 Form Post 到 gateway。</li>
 *   <li>{@link #queryTrade} — 单笔交易查询：幕后 POST QueryTradeInfo，返回 JSON。</li>
 * </ul>
 *
 * <p>多门店：每个门店在蓝新申请独立 HashKey/HashIV，调用时传入 {@link NewebPayConfig}。
 * 仿 {@code com.ruoyi.app.utils.ezPay.EzPay} 结构。
 *
 * @author ruoyi
 * @date 2026-06-22
 */
@Component
public class NewebPay {

    /** 正式环境根地址。 */
    public static final String BASE_PROD = "https://core.newebpay.com";
    /** 测试环境根地址。 */
    public static final String BASE_TEST = "https://ccore.newebpay.com";

    /** MPG 幕前支付 gateway。 */
    public static final String URL_MPG_GATEWAY = "/MPG/mpg_gateway";
    /** 单笔交易查询。 */
    public static final String URL_QUERY_TRADE_INFO = "/API/QueryTradeInfo";

    /**
     * MPG 幕前支付：组装加密 form 字段（不直接 POST，由前端 Form Post 到 gateway）。
     *
     * <p>对应 NDNF §4.2.1 + §4.1.1/4.1.2：tradeParams → http_build_query → AES 加密 TradeInfo →
     * SHA256 生成 TradeSha → 连同 MerchantID/Version/EncryptType 返回。
     *
     * @param baseUrl      {@link #BASE_PROD} 或 {@link #BASE_TEST}
     * @param cfg          门店配置
     * @param tradeParams  TradeInfo 内含字段（MerchantID/RespondType/TimeStamp/Version/MerchantOrderNo/
     *                     Amt/ItemDesc/NotifyURL/ReturnURL/CREDIT/LINEPAY/APPLEPAY 等）
     * @param version      串接程式版本（如 "2.3"）
     * @return form 字段：gatewayUrl / MerchantID / TradeInfo / TradeSha / Version / EncryptType
     */
    public Map<String, String> createMpgForm(String baseUrl, NewebPayConfig cfg,
                                              Map<String, Object> tradeParams, String version) {
        String query = buildQuery(tradeParams);
        String tradeInfo = NewebPayEncryptUtil.encrypt(query, cfg.getHashKey(), cfg.getHashIv());
        String tradeSha = NewebPayEncryptUtil.genTradeSha(tradeInfo, cfg.getHashKey(), cfg.getHashIv());
        Map<String, String> form = new LinkedHashMap<>();
        form.put("gatewayUrl", baseUrl + URL_MPG_GATEWAY);
        form.put("MerchantID", cfg.getMerchantId());
        form.put("TradeInfo", tradeInfo);
        form.put("TradeSha", tradeSha);
        form.put("Version", version);
        form.put("EncryptType", "0"); // 0 = AES/CBC/PKCS7Padding（默认）
        return form;
    }

    /**
     * 单笔交易查询（幕后 POST，返回 JSON）。对应 NDNF §4.3。
     *
     * @param baseUrl         {@link #BASE_PROD} 或 {@link #BASE_TEST}
     * @param cfg             门店配置
     * @param amt             订单金额
     * @param merchantOrderNo 商店订单号
     * @return 蓝新回应 JSON（Status/Message/Result，Result 内含 TradeStatus/PaymentType/PayTime/CheckCode 等）
     */
    public JSONObject queryTrade(String baseUrl, NewebPayConfig cfg, String amt, String merchantOrderNo) throws Exception {
        String checkValue = NewebPayEncryptUtil.genCheckValue(
                amt, cfg.getMerchantId(), merchantOrderNo, cfg.getHashKey(), cfg.getHashIv());
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("MerchantID", cfg.getMerchantId()));
        params.add(new BasicNameValuePair("Version", "1.3"));
        params.add(new BasicNameValuePair("RespondType", "JSON"));
        params.add(new BasicNameValuePair("CheckValue", checkValue));
        params.add(new BasicNameValuePair("TimeStamp", String.valueOf(System.currentTimeMillis() / 1000L)));
        params.add(new BasicNameValuePair("MerchantOrderNo", merchantOrderNo));
        params.add(new BasicNameValuePair("Amt", amt));
        String resp = postFormRaw(baseUrl + URL_QUERY_TRADE_INFO, params);
        return JSON.parseObject(resp);
    }

    /**
     * 后台 POST（urlencoded form），返回响应体字符串。
     */
    private static String postFormRaw(String url, List<NameValuePair> params) throws Exception {
        HttpPost post = new HttpPost(url);
        post.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
        try (CloseableHttpClient client = HttpClients.createDefault();
             CloseableHttpResponse res = client.execute(post)) {
            return EntityUtils.toString(res.getEntity(), StandardCharsets.UTF_8);
        }
    }

    /**
     * 模拟 PHP http_build_query：key、value 均做 URL 编码，用 & 连接。null 值跳过。
     */
    static String buildQuery(Map<String, Object> params) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> e : params.entrySet()) {
            if (e.getValue() == null) {
                continue;
            }
            if (sb.length() > 0) {
                sb.append('&');
            }
            sb.append(URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8))
                    .append('=')
                    .append(URLEncoder.encode(String.valueOf(e.getValue()), StandardCharsets.UTF_8));
        }
        return sb.toString();
    }
}
