package com.liquidnet.service.goblin.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.liquidnet.commons.lang.util.HttpUtil;
import com.liquidnet.commons.lang.util.MD5Utils;
import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.response.OrderCreateResponse;
import com.liquidnet.service.goblin.param.shouqianba.response.SettlementCreateResponse;
import com.liquidnet.service.goblin.param.shouqianba.response.data.*;
import com.liquidnet.service.goblin.service.IGoblinShouQianBaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.TreeMap;

/**
 * 收钱吧对接实现类
 *
 * @author liquidnet
 * @since 2026-03-16
 */
@Slf4j
@Service
public class GoblinShouQianBaServiceImpl implements IGoblinShouQianBaService {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    // TODO: 先写固定常量，后期可配置文件化
    public static final String BASE_API = "https://api.shouqianba.com";
    private static final String APPID = "test_appid";
    private static final String APPKEY = "test_appkey";
    // TODO: 收钱吧公钥，建议改为配置
    private static final String SHOUQIANBA_PUB_KEY = "test_pub_key";

    /**
     * 创建结算明细
     *
     * @param request 创建结算明细请求参数
     * @return 收钱吧响应结果；调用失败时返回 null
     */
    @Override
    public SettlementCreateData createSettlement(SettlementCreateRequest request) {
        final String url = BASE_API + "/optimus/core/mall/createPreOrder";
        log.info("[收钱吧] 创建结算明细, 请求URL: {}, 请求参数: {}", url, request);

        try {
            // body进行序列化成TreeMap以后 最后转成json（为了排序稳定）
            TreeMap<String, Object> map = objectMapper.convertValue(
                    request,
                    new TypeReference<TreeMap<String, Object>>() {
                    }
            );
            String requestBody = objectMapper.writeValueAsString(map);

            // 构建请求头（添加签名参数）
            MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
            headers.add("Authorization", getSign(requestBody));

            String responseStr = HttpUtil.postJson(url, requestBody, headers);
            log.info("[收钱吧] 创建结算明细, 响应体: {}", responseStr);

            // 转换响应报文
            SettlementCreateResponse response = objectMapper.readValue(responseStr, SettlementCreateResponse.class);
            if (response != null && Boolean.TRUE.equals(response.getSuccess())) {
                return response.getData();
            } else {
                log.error("[收钱吧] 创建结算明细业务失败, code: {}, msg: {}",
                        response != null ? response.getCode() : "null",
                        response != null ? response.getMsg() : "null");
                return null;
            }
        } catch (Exception e) {
            log.error("[收钱吧] 创建结算明细发生异常, 请求参数: {}", request, e);
            return null;
        }
    }

    @Override
    public OrderCreateData createOrder(OrderCreateRequest request) {
        final String url = BASE_API + "/optimus/core/order/placeOrder";
        log.info("[收钱吧] 创建订单, 请求URL: {}, 请求参数: {}", url, request);

        try {
            // body进行序列化成TreeMap以后 最后转成json（为了排序稳定）
            TreeMap<String, Object> map = objectMapper.convertValue(
                    request,
                    new TypeReference<TreeMap<String, Object>>() {
                    }
            );
            String requestBody = objectMapper.writeValueAsString(map);

            // 构建请求头（添加签名参数）
            MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
            headers.add("Authorization", getSign(requestBody));

            String responseStr = HttpUtil.postJson(url, requestBody, headers);
            log.info("[收钱吧] 创建订单, 响应体: {}", responseStr);

            // 转换响应报文
            OrderCreateResponse response = objectMapper.readValue(responseStr, OrderCreateResponse.class);
            if (response != null && Boolean.TRUE.equals(response.getSuccess())) {
                return response.getData();
            } else {
                log.error("[收钱吧] 创建订单失败, code: {}, msg: {}",
                        response != null ? response.getCode() : "null",
                        response != null ? response.getMsg() : "null");
                return null;
            }
        } catch (Exception e) {
            log.error("[收钱吧] 创建订单发生异常, 请求参数: {}", request, e);
            return null;
        }
    }

    @Override
    public AcquiringCreateData createAcquiring(AcquiringCreateRequest request) {
        return null;
    }

    @Override
    public CashierQueryData queryCashier(CashierQueryRequest request) {

        return null;
    }

    @Override
    public CreateWechatPrepayOrderData createWechatPrepayOrder(CreateWechatPrepayOrderRequest request) {
        return null;
    }

    @Override
    public CouponQueryData queryCoupon(CouponQueryRequest request) {
        return null;
    }

    @Override
    public boolean syncCouponStatus(CouponStatusSyncRequest request) {
        return false;
    }

    @Override
    public CouponRefundData refundCoupon(CouponRefundRequest request) {
        return null;
    }

    private String getSign(String bodyJsonStr) {
        try {
            // 签名算法: sign = MD5( CONCAT( body + appkey ) )
            String rawStr = bodyJsonStr + APPKEY;
            String sign = MD5Utils.md5(rawStr);

            // 签名首部: Authorization: appid + " " + sign
            return APPID + " " + sign;
        } catch (Exception e) {
            log.error("[收钱吧] 生成签名发生异常", e);
            return "";
        }
    }

    /**
     * 收钱吧回调推送验签
     *
     * @param signature 收钱吧推送来的签名 (signature)
     * @param eventId   事件ID (eventId)
     * @param timestamp 时间戳 (timestamp)
     * @param nonce     随机数 (nonce)
     * @param content   业务数据报文 (content)
     * @return 验签是否通过
     */
    public boolean verifySignature(String signature, String eventId, String timestamp, String nonce, String content) {
        // 签名原串 = eventId + timestamp + nonce + content
        String plaintext = eventId + timestamp + nonce + content;
        return verifySignatureSHA256WithRSA(plaintext, signature, SHOUQIANBA_PUB_KEY);
    }

    public boolean verifySignatureSHA256WithRSA(String plaintext, String inputSignature, String pubKey) {
        return verifySignatureSHA256WithRSA(plaintext.getBytes(StandardCharsets.UTF_8), inputSignature, pubKey);
    }

    public boolean verifySignatureSHA256WithRSA(byte[] plaintextByte, String inputSignature, String pubKey) {
        try {
            X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(bobPubKeySpec);
            byte[] signed = Base64.getDecoder().decode(inputSignature);
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initVerify(publicKey);
            signature.update(plaintextByte);
            return signature.verify(signed);
        } catch (Exception e) {
            log.error("[收钱吧] 验签异常, signature={}, pubKey={}", inputSignature, pubKey, e);
            return false;
        }
    }
}
