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.config.properties.ShouqianbaProperties;
import com.liquidnet.service.goblin.param.shouqianba.callback.CallbackParams;
import com.liquidnet.service.goblin.param.shouqianba.request.*;
import com.liquidnet.service.goblin.param.shouqianba.response.*;
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.List;
import java.util.TreeMap;

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


    private final ShouqianbaProperties shouqianbaProperties;

    public GoblinShouQianBaServiceImpl(ShouqianbaProperties properties) {
        this.shouqianbaProperties = properties;
        if (this.shouqianbaProperties == null) {
            throw new IllegalArgumentException("找不到应用配置");
        }
    }

    private static final ObjectMapper objectMapper = new ObjectMapper();


    /**
     * 创建结算明细
     *
     * @param request 创建结算明细请求参数
     * @return 收钱吧响应结果；调用失败时返回 null
     */
    @Override
    public SettlementCreateData createSettlement(SettlementCreateRequest request) {
        return executeShouQianBaRequest("/optimus/core/mall/createCheckoutItems", "创建结算明细", request, SettlementCreateResponse.class);
    }

    /**
     * 创建订单
     *
     * @param request
     * @return
     */
    @Override
    public OrderCreateData createOrder(OrderCreateRequest request) {
        return executeShouQianBaRequest("/optimus/core/order/placeOrder", "创建订单", request, OrderCreateResponse.class);
    }

    /**
     * 创建收单
     * 如果上一步创建收单失败 可以使用这个接口重新创建收单
     *
     * @return
     */
    @Override
    public AcquiringCreateData createAcquiring(AcquiringCreateRequest request) {
        return executeShouQianBaRequest("/optimus/core/order/createAcquiring", "创建收单环节", request, AcquiringCreateResponse.class);
    }

    /**
     * 查询收银台
     *
     * @param request
     * @return
     */
    @Override
    public CashierQueryData queryCashier(CashierQueryRequest request) {
        return executeShouQianBaRequest("/optimus/core/cashier/queryCashierPage", "查询收银台", request, CashierQueryResponse.class);
    }

    /**
     * 创建微信预支付订单
     *
     * @param request
     * @return
     */
    @Override
    public CreateWechatPrepayOrderData createWechatPrepayOrder(CreateWechatPrepayOrderRequest request) {
        return executeShouQianBaRequest("/optimus/core/cashier/proxyPreCreatedPay", "创建微信预支付订单", request, CreateWechatPrepayOrderResponse.class);
    }

    /**
     * 查询券码
     *
     * @param request
     * @return
     */
    @Override
    public CouponQueryData queryCoupon(CouponQueryRequest request) {
        return executeShouQianBaRequest("/optimus/core/voucher/queryOrderVoucherList", "查询优惠券", request, CouponQueryResponse.class);
    }

    /**
     * 券码状态同步
     *
     * @param request
     * @return
     */
    @Override
    public boolean syncCouponStatus(CouponStatusSyncRequest request) {
        CouponStatusSyncResponse response = executeRequestAndGetResponse("/optimus/core/voucher/modifyOrderVoucherList", "同步优惠券状态", request, CouponStatusSyncResponse.class);
        return response != null && Boolean.TRUE.equals(response.getSuccess());
    }

    /**
     * 券退款
     *
     * @param request
     * @return
     */
    @Override
    public CouponRefundData refundCoupon(CouponRefundRequest request) {
        return executeShouQianBaRequest("/optimus/core/aftersale/applyRefund", "退款优惠券", request, CouponRefundResponse.class);
    }

    /**
     * 商城列表接口
     *
     * @param request
     * @return
     */
    @Override
    public List<MallListQueryData> queryMallList(MallListQueryRequest request) {
        return executeShouQianBaRequest("/optimus/open/mall/queryMallList", "查询门店列表", request, MallListQueryResponse.class);
    }

    /**
     * 商城商品接口
     *
     * @param request
     * @return
     */
    @Override
    public List<MallProductsQueryData> queryMallProducts(MallProductsQueryRequest request) {
        return executeShouQianBaRequest("/optimus/open/mall/queryMallProducts", "查询门店商品", request, MallProductsQueryResponse.class);
    }

    /**
     * 发送HTTP请求并返回Response对象
     */
    private <T extends BaseResponse<?>> T executeRequestAndGetResponse(
            String apiPath, String businessName, Object request, Class<T> responseClass) {
        final String url = shouqianbaProperties.getBaseApi() + apiPath;
        log.info("[收钱吧] {}, 请求URL: {}, 请求参数: {}", businessName, 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("[收钱吧] {}, 响应体: {}", businessName, responseStr);

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

    /**
     * 封装收钱吧接口调用，提取公共逻辑并发起请求，默认返回Data
     */
    private <D, T extends BaseResponse<D>> D executeShouQianBaRequest(
            String apiPath, String businessName, Object request, Class<T> responseClass) {
        T response = executeRequestAndGetResponse(apiPath, businessName, request, responseClass);
        if (response != null && Boolean.TRUE.equals(response.getSuccess())) {
            return response.getData();
        }
        return null;
    }

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

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

    /**
     * 收钱吧回调推送验签
     *
     * @param callbackParams@return 验签是否通过
     */
    public boolean verifySignature(CallbackParams callbackParams) {
        // 签名原串 = eventId + timestamp + nonce + content
        String plaintext = callbackParams.getEventId() + callbackParams.getTimestamp() + callbackParams.getNonce() + callbackParams.getContent();
        return verifySignatureSHA256WithRSA(plaintext, callbackParams.getSignature(), shouqianbaProperties.getPublicKey());
    }

    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;
        }
    }
}
