package cn.iocoder.yudao.module.system.util.pay;

import cn.iocoder.yudao.module.system.controller.admin.pay.vo.CcbCloseOrderRequestVO;
import cn.iocoder.yudao.module.system.controller.admin.pay.vo.CcbPayRequest;
import cn.iocoder.yudao.module.system.controller.admin.pay.vo.WxPayParams;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
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.HttpGet;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class CcbPayUtils {
    private static final Logger log = LoggerFactory.getLogger(CcbPayUtils.class);

    // 文档规定的签名字段顺序（必传+关键条件字段）
    private static final List<String> SIGN_FIELD_ORDER = new ArrayList<>();
    static {
        // 按文档要求+当前回调字段顺序排列（有值/空值均参与，无此字段则跳过）
        SIGN_FIELD_ORDER.add("POSID");
        SIGN_FIELD_ORDER.add("BRANCHID");
        SIGN_FIELD_ORDER.add("ORDERID");
        SIGN_FIELD_ORDER.add("PAYMENT");
        SIGN_FIELD_ORDER.add("CURCODE");
        SIGN_FIELD_ORDER.add("REMARK1");
        SIGN_FIELD_ORDER.add("REMARK2");
        SIGN_FIELD_ORDER.add("ACC_TYPE");
        SIGN_FIELD_ORDER.add("SUCCESS");
        SIGN_FIELD_ORDER.add("TYPE");
        SIGN_FIELD_ORDER.add("REFERER");
        SIGN_FIELD_ORDER.add("CLIENTIP");
        SIGN_FIELD_ORDER.add("ACCDATE");
    }

    // 生成MAC值（空值参与，无escape）
    public static String generateMac(CcbPayRequest request) {
        StringBuilder sb = new StringBuilder();
        for (String field : CcbPayConstant.MAC_ORDER) {
            String value = getFieldValue(request, field);
            sb.append(field).append("=").append(value).append("&");
        }
        // 移除最后一个&，MD5加密转大写
        String source = sb.substring(0, sb.length() - 1);
        log.info("MAC摘要原串：{}", source);
        return DigestUtils.md5Hex(source.getBytes(StandardCharsets.UTF_8));

    }

    public static String sendRequest(CcbPayRequest request) throws Exception {
        // 构建请求参数（按文档顺序）
        List<NameValuePair> params = new ArrayList<>();
        for (String field : CcbPayConstant.REQUEST_ORDER) {
            String value = getFieldValue(request, field);
            params.add(new BasicNameValuePair(field, value));
        }
        log.info("请求payurl参数：{}", JSON.toJSONString(params));
        // 发送POST请求
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            HttpPost post = new HttpPost(CcbPayConstant.PAY_URL);
            post.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));

            try (CloseableHttpResponse response = client.execute(post)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    String resp = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                    log.info("建行微信下单响应：{}", resp);
                    return resp;
                }
                throw new Exception("建行下单接口无响应");
            }
        }
    }

    private static String getFieldValue(CcbPayRequest request, String field) {
        switch (field) {
            case "MERCHANTID":
                return request.getMerchantId();
            case "POSID":
                return request.getPosId();
            case "BRANCHID":
                return request.getBranchId();
            case "ORDERID":
                return request.getOrderId();
            case "PAYMENT":
                return String.valueOf(request.getPayment());
            case "CURCODE":
                return request.getCurCode();
            case "TXCODE":
                return request.getTxCode();
            case "REMARK1":
                return request.getRemark1();
            case "REMARK2":
                return request.getRemark2();
            case "TYPE":
                return request.getType();
            case "PUB":
                return request.getPub();
            case "GATEWAY":
                return request.getGateway();
            case "CLIENTIP":
                return request.getClientIp();
            case "REGINFO":
                return request.getRegInfo(); // 不escape，直接传中文
            case "PROINFO":
                return request.getProInfo(); // 不escape，直接传中文
            case "REFERER":
                return request.getReferer();
            case "TRADE_TYPE":
                return request.getTradeType();
            case "SUB_APPID":
                return request.getSubAppId();
            case "SUB_OPENID":
                return request.getSubOpenId();
            case "MAC":
                return request.getMac();
            default:
                return ""; // 默认返回空字符串，确保空值拼接
        }
    }

    /**
     * 新增：请求PAYURL，获取微信支付参数
     *
     * @param payUrl 统一下单接口返回的PAYURL（如 https://ibsbjstar.ccb.com.cn/CCBIS/B2CMainPlat_03_EPAY?...）
     * @return 微信支付参数实体（含timeStamp、paySign等）
     * @throws Exception HTTP请求异常或响应解析异常
     */
    public static WxPayParams requestPayUrl(String payUrl) throws Exception {
        Logger log = LoggerFactory.getLogger(CcbPayUtils.class);
        if (payUrl == null || payUrl.isEmpty()) {
            throw new Exception("PAYURL为空，无法请求微信支付参数");
        }
        log.info("请求PAYURL获取微信支付参数：{}", payUrl);

        // 1. 用HTTP GET方式请求PAYURL（建行PAYURL是带参数的完整URL，适合GET）
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpGet httpGet = new HttpGet(payUrl);
            // 2. 发送请求并获取响应
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                // 3. 解析响应（建行返回JSON格式的微信支付参数）
                String responseStr = EntityUtils.toString(
                        response.getEntity(),
                        StandardCharsets.UTF_8
                );
                log.info("PAYURL请求响应：{}", responseStr);

                // 4. 转换为微信支付参数实体
                WxPayParams wxPayParams = JSON.parseObject(responseStr, WxPayParams.class);
                if (wxPayParams == null) {
                    throw new Exception("PAYURL响应解析失败，响应内容：" + responseStr);
                }

                // 5. 校验业务结果（ERRCODE=000000表示成功）
                if (!"true".equals(wxPayParams.getSuccess()) || !"000000".equals(wxPayParams.getErrCode())) {
                    log.error("PAYURL请求失败：错误码[" + wxPayParams.getErrCode() + "]，错误信息[" + wxPayParams.getErrMsg() + "]");
                }
                return wxPayParams;
            }
        } catch (Exception e) {
            log.error("PAYURL请求异常", e);
            throw e; // 抛出异常，由业务层处理
        }
    }

    public static String generateCloseOrderMac(CcbCloseOrderRequestVO request) {
        // 严格按文档字段顺序拼接（必传字段，无值传空字符串，不可省略）
        StringBuilder macSource = new StringBuilder();
        macSource.append("MERCHANTID=").append(request.getMERCHANTID())
                .append("&POSID=").append(request.getPOSID())
                .append("&BRANCHID=").append(request.getBRANCHID())
                .append("&ORDERID=").append(request.getORDERID());

        // 标准MD5加密（UTF-8编码）
        return DigestUtils.md5Hex(macSource.toString().getBytes());
    }

    public static String sendCloseOrderRequest(CcbCloseOrderRequestVO request) throws Exception {
        // 1. 创建HTTP客户端
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            // 2. 构建POST请求
            HttpPost httpPost = new HttpPost(CcbPayConstant.PAY_URL);

            // 3. 封装请求参数（按文档字段传递，含必选和可选）
            List<NameValuePair> params = new ArrayList<>();
            params.add(new BasicNameValuePair("MERCHANTID", request.getMERCHANTID()));
            params.add(new BasicNameValuePair("POSID", request.getPOSID()));
            params.add(new BasicNameValuePair("BRANCHID", request.getBRANCHID()));
            params.add(new BasicNameValuePair("ORDERID", request.getORDERID()));
            params.add(new BasicNameValuePair("TXCODE", CcbPayConstant.CLOSE_TXCODE));
            params.add(new BasicNameValuePair("MAC", request.getMAC()));
            // 可选字段：SUB_APPID（非必传，有值才添加）
            if (request.getSUB_APPID() != null && !request.getSUB_APPID().isEmpty()) {
                params.add(new BasicNameValuePair("SUB_APPID", request.getSUB_APPID()));
            }

            // 4. 设置请求体（表单格式，符合HTTP POST标准）
            HttpEntity entity = new UrlEncodedFormEntity(params, "UTF-8");
            httpPost.setEntity(entity);

            // 5. 发送请求并获取响应
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                // 6. 解析响应（建行返回JSON字符串）
                HttpEntity responseEntity = response.getEntity();
                if (responseEntity != null) {
                    String responseStr = EntityUtils.toString(responseEntity, "UTF-8");
                    log.info("关闭订单接口响应：{}，订单号：{}", responseStr, request.getORDERID());
                    return responseStr;
                }
                throw new Exception("关闭订单接口无响应，订单号：" + request.getORDERID());
            }
        } catch (Exception e) {
            log.error("关闭订单HTTP请求异常，订单号：{}", request.getORDERID(), e);
            throw e;
        }
    }

    /**
     * 构建签名原串（按文档顺序，空值不跳过）
     */
    public static String buildSignSource(Map<String, String> paramMap) {
        StringBuilder sb = new StringBuilder();
        for (String field : SIGN_FIELD_ORDER) {
            String value = getMapValue(paramMap, field);
            sb.append(field).append("=").append(value).append("&");
        }
        // 移除最后一个&
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }



    /**
     * 安全获取Map值（避免空指针，空值返回空字符串）
     */
    public static String getMapValue(Map<String, String> paramMap, String key) {
        return paramMap.getOrDefault(key, "").trim(); // 去除首尾空格，避免格式问题
    }
}
