package org.dromara.pay.core.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.pay.core.PayStrategy;
import org.dromara.pay.core.PayStrategyFactory;
import org.dromara.pay.domain.PayChannel;
import org.dromara.pay.domain.PayOrder;
import org.dromara.pay.domain.PayRefund;
import org.dromara.pay.domain.vo.PayNotifyResult;
import org.dromara.pay.domain.vo.PayOrderSubmitRespVO;
import org.dromara.pay.enums.PayChannelEnum;
import org.dromara.pay.enums.PayOrderStatusEnum;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 支付宝支付策略
 *
 * @author pengles
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class AlipayStrategy implements PayStrategy {

    private final PayStrategyFactory payStrategyFactory;

    @PostConstruct
    public void init() {
        payStrategyFactory.register(PayChannelEnum.ALIPAY_PC.getCode(), this);
        payStrategyFactory.register(PayChannelEnum.ALIPAY_WAP.getCode(), this);
        payStrategyFactory.register(PayChannelEnum.ALIPAY_APP.getCode(), this);
        payStrategyFactory.register(PayChannelEnum.ALIPAY_QR.getCode(), this);
    }

    @Override
    public PayOrderSubmitRespVO unifiedOrder(PayOrder order, PayChannel channel) {
        AlipayClient client = getClient(channel.getConfig());
        String code = channel.getCode();
        PayOrderSubmitRespVO resp = new PayOrderSubmitRespVO();
        resp.setPayOrderNo(order.getNo());
        resp.setStatus(0); // WAITING

        try {
            if (PayChannelEnum.ALIPAY_PC.getCode().equals(code)) {
                AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
                request.setNotifyUrl(order.getNotifyUrl());
                request.setReturnUrl(order.getNotifyUrl()); // 暂时复用
                AlipayTradePagePayModel model = new AlipayTradePagePayModel();
                model.setOutTradeNo(order.getNo());
                model.setSubject(order.getSubject());
                model.setTotalAmount(String.valueOf(order.getPrice() / 100.0));
                model.setProductCode("FAST_INSTANT_TRADE_PAY");
                request.setBizModel(model);
                AlipayTradePagePayResponse response = client.pageExecute(request);
                resp.setPayData(response.getBody());
            } else if (PayChannelEnum.ALIPAY_WAP.getCode().equals(code)) {
                AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
                request.setNotifyUrl(order.getNotifyUrl());
                AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
                model.setOutTradeNo(order.getNo());
                model.setSubject(order.getSubject());
                model.setTotalAmount(String.valueOf(order.getPrice() / 100.0));
                model.setProductCode("QUICK_WAP_WAY");
                request.setBizModel(model);
                AlipayTradeWapPayResponse response = client.pageExecute(request);
                resp.setPayData(response.getBody());
            } else if (PayChannelEnum.ALIPAY_APP.getCode().equals(code)) {
                AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
                request.setNotifyUrl(order.getNotifyUrl());
                AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                model.setOutTradeNo(order.getNo());
                model.setSubject(order.getSubject());
                model.setTotalAmount(String.valueOf(order.getPrice() / 100.0));
                model.setProductCode("QUICK_MSECURITY_PAY");
                request.setBizModel(model);
                AlipayTradeAppPayResponse response = client.sdkExecute(request);
                resp.setPayData(response.getBody());
            } else if (PayChannelEnum.ALIPAY_QR.getCode().equals(code)) {
                AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
                request.setNotifyUrl(order.getNotifyUrl());
                AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
                model.setOutTradeNo(order.getNo());
                model.setSubject(order.getSubject());
                model.setTotalAmount(String.valueOf(order.getPrice() / 100.0));
                request.setBizModel(model);
                AlipayTradePrecreateResponse response = client.execute(request);
                resp.setPayData(response.getQrCode());
            }
        } catch (AlipayApiException e) {
            log.error("支付宝下单失败", e);
            throw new ServiceException("支付宝下单失败: " + e.getMessage());
        }
        return resp;
    }

    @Override
    public Boolean refund(PayRefund refund, PayChannel channel) {
        AlipayClient client = getClient(channel.getConfig());
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
        model.setOutTradeNo(refund.getOrderNo());
        model.setRefundAmount(String.valueOf(refund.getRefundPrice() / 100.0));
        model.setRefundReason(refund.getReason());
        model.setOutRequestNo(refund.getNo());
        request.setBizModel(model);
        try {
            AlipayTradeRefundResponse response = client.execute(request);
            if (response.isSuccess()) {
                refund.setChannelRefundNo(response.getTradeNo()); // 支付宝可能不返回退款单号，用TradeNo暂代
                return true;
            } else {
                refund.setErrorMsg(response.getSubMsg());
                refund.setErrorCode(response.getSubCode());
                return false;
            }
        } catch (AlipayApiException e) {
            log.error("支付宝退款失败", e);
            throw new ServiceException("支付宝退款失败: " + e.getMessage());
        }
    }

    @Override
    public Integer queryOrder(PayOrder order, PayChannel channel) {
        AlipayClient client = getClient(channel.getConfig());
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(order.getNo());
        request.setBizModel(model);
        try {
            AlipayTradeQueryResponse response = client.execute(request);
            if (response.isSuccess()) {
                if ("TRADE_SUCCESS".equals(response.getTradeStatus()) || "TRADE_FINISHED".equals(response.getTradeStatus())) {
                    return PayOrderStatusEnum.SUCCESS.getStatus();
                } else if ("TRADE_CLOSED".equals(response.getTradeStatus())) {
                    return PayOrderStatusEnum.CLOSED.getStatus();
                }
            }
        } catch (AlipayApiException e) {
            log.error("支付宝查单失败", e);
        }
        return PayOrderStatusEnum.WAITING.getStatus();
    }

    @Override
    public Boolean closeOrder(PayOrder order, PayChannel channel) {
        AlipayClient client = getClient(channel.getConfig());
        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        AlipayTradeCloseModel model = new AlipayTradeCloseModel();
        model.setOutTradeNo(order.getNo());
        request.setBizModel(model);
        try {
            AlipayTradeCloseResponse response = client.execute(request);
            if (response.isSuccess()) {
                log.info("支付宝关单成功: {}", order.getNo());
                return true;
            } else {
                log.error("支付宝关单失败: {}", response.getSubMsg());
                return false;
            }
        } catch (AlipayApiException e) {
             log.error("支付宝关单异常", e);
             return false;
        }
    }

    @Override
    public Integer queryRefund(PayRefund refund, PayChannel channel) {
        AlipayClient client = getClient(channel.getConfig());
        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
        model.setOutTradeNo(refund.getOrderNo());
        model.setOutRequestNo(refund.getNo());
        request.setBizModel(model);
        try {
             AlipayTradeFastpayRefundQueryResponse response = client.execute(request);
             if (response.isSuccess()) {
                 // 支付宝查询退款成功，一般表示退款成功，因为如果退款不存在会报错或返回空
                 if (StrUtil.isNotBlank(response.getRefundAmount())) {
                      return 10; // SUCCESS
                 }
             }
        } catch (AlipayApiException e) {
             log.error("支付宝退款查询失败", e);
        }
        return 0; // WAITING or UNKNOWN
    }

    @Override
    public PayNotifyResult processNotify(HttpServletRequest request, PayChannel channel) {
        PayNotifyResult result = new PayNotifyResult();
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        
        Map<String, Object> config = JsonUtils.parseMap(channel.getConfig());
        String alipayPublicKey = (String) config.get("publicKey");
        String signType = (String) config.get("signType");
        String charset = "UTF-8"; // 默认UTF-8

        try {
            boolean verify = AlipaySignature.rsaCheckV1(params, alipayPublicKey, charset, signType);
            result.setSuccess(verify);
            if (verify) {
                result.setOrderNo(params.get("out_trade_no"));
                result.setTradeNo(params.get("trade_no"));
                result.setResponseBody("success");
            } else {
                result.setResponseBody("failure");
            }
        } catch (AlipayApiException e) {
            log.error("支付宝回调验签异常", e);
            result.setSuccess(false);
            result.setResponseBody("failure");
        }
        return result;
    }

    private AlipayClient getClient(String configJson) {
        Map<String, Object> config = JsonUtils.parseMap(configJson);
        return new DefaultAlipayClient(
                (String) config.get("serverUrl"),
                (String) config.get("appId"),
                (String) config.get("privateKey"),
                "json",
                "UTF-8",
                (String) config.get("publicKey"),
                (String) config.get("signType")
        );
    }
}
