package com.ruoyi.common.pay.ali.service;

import cn.hutool.json.JSONObject;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeCreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeCloseRequest;
import com.alipay.api.request.AlipayTradeCreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeCloseResponse;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.ruoyi.common.auth.ali.AliConfig;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.pay.PayApi;
import com.ruoyi.common.pay.Payable;
import com.ruoyi.common.pay.Refundable;
import com.ruoyi.common.pay.ali.enums.AliTradeStatusEnum;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * @author wjh
 * 2024/12/10
 */
@Service
public class AliPayService implements PayApi {

    public String pay(Payable payable, Object config) {
        // 初始化支付宝客户端
        AliConfig aliConfig = (AliConfig) config;
        AlipayClient alipayClient = aliConfig.alipayClient();

        // 构造请求参数以调用接口
        AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
        AlipayTradeCreateModel data = new AlipayTradeCreateModel();
        // 设置商户订单号
        data.setOutTradeNo(payable.payableOutTradeNo());
        // 设置产品码
        data.setProductCode("JSAPI_PAY");
        // 设置小程序appId
        data.setOpAppId(aliConfig.getAppId());
        // 设置订单总金额（元）
        data.setTotalAmount(payable.payableYuan().toString());
        // 设置订单标题
        data.setSubject(payable.payableDescription());
        // 设置订单附加信息
        data.setBody(payable.payableAttach());
        // 设置买家支付宝用户唯一标识
        data.setBuyerOpenId(payable.payableAccount());
        request.setBizModel(data);
        request.setNotifyUrl(aliConfig.getNotifyUrl());

        try {
            AlipayTradeCreateResponse response = alipayClient.certificateExecute(request);
            ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
            return response.getTradeNo();
        } catch (Exception e) {
            throw new ServiceException("调用支付宝下单失败：" + e.getMessage());
        }
    }

    /**
     * 关闭支付订单
     */
    public void closeByOutTradeNo(String outTradeNo, Object config) {
        // 初始化支付宝客户端
        AliConfig aliConfig = (AliConfig) config;
        AlipayClient alipayClient = aliConfig.alipayClient();


        AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", outTradeNo);
        request.setBizContent(bizContent.toString());
        try {
            AlipayTradeCloseResponse response = alipayClient.certificateExecute(request);
            ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
        } catch (Exception e) {
            throw new ServiceException("调用支付宝关闭订单失败：" + e.getMessage());
        }
    }


    public AlipayTradeQueryResponse queryByOutTradeNo(String outTradeNo, LocalDate orderDate, Object config) {
        // 初始化支付宝客户端
        AliConfig aliConfig = (AliConfig) config;
        AlipayClient alipayClient = aliConfig.alipayClient();

        // 构造请求参数以调用接口
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();

        // 设置订单支付时传入的商户订单号
        model.setOutTradeNo(outTradeNo);
        request.setBizModel(model);

        try {
            AlipayTradeQueryResponse response = alipayClient.certificateExecute(request);
            ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
            return response;
        } catch (Exception e) {
            throw new ServiceException("调用支付宝查询订单失败：" + e.getMessage());
        }
    }


    /**
     * 发起退款
     *
     * @param refund
     * @param config
     */
    public AlipayTradeRefundResponse refund(Refundable refund, Object config) {

        // 初始化支付宝客户端
        AliConfig aliConfig = (AliConfig) config;
        AlipayClient alipayClient = aliConfig.alipayClient();

        // 构造请求参数以调用接口
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel model = new AlipayTradeRefundModel();

        // 设置商户订单号
        model.setOutTradeNo(refund.refundOutTradeNo());
        // 设置退款金额
        model.setRefundAmount(refund.refundAmountYuan().toString());
        // 设置退款原因说明
        model.setRefundReason(refund.refundReason());
        // 设置退款请求号
        model.setOutRequestNo(refund.refundOutRefundNo());
        request.setBizModel(model);
        request.setNotifyUrl(aliConfig.getNotifyUrl());

        try {
            AlipayTradeRefundResponse response = alipayClient.certificateExecute(request);
            ServiceUtil.assertion(!response.isSuccess(), response.getMsg());
            ServiceUtil.assertion(!"Y".equals(response.getFundChange()), "退款失败，本次退款未导致资金变化");
            return response;
        } catch (Exception e) {
            throw new ServiceException("调用支付宝退款失败：" + e.getMessage());
        }
    }

    @Override
    public boolean isPaySuccessByOutTradeNo(String outTradeNo, LocalDate orderDate, Object config) {
        AlipayTradeQueryResponse res = this.queryByOutTradeNo(outTradeNo, orderDate, config);
        return isPaySuccess(res);
    }

    @Override
    public boolean isPaySuccess(Object result) {
        AlipayTradeQueryResponse res = (AlipayTradeQueryResponse) result;
        return res != null && AliTradeStatusEnum.TRADE_SUCCESS.getStatus().equals(res.getTradeStatus());
    }

    @Override
    public LocalDateTime getPayTime(Object result) {
        AlipayTradeQueryResponse res = (AlipayTradeQueryResponse) result;
        return DateUtils.toLocalDateTime(res.getSendPayDate());
    }

    /**
     * 对通知进行验签
     * @param params 参数
     * @param aliCertPath 支付宝公钥证书路径
     */
    public void checkNotifySign(Map<String, String> params, String aliCertPath) {
        //调用SDK验证签名
        try {
            boolean signVerified = AlipaySignature.rsaCertCheckV1(params, aliCertPath,"UTF-8","RSA2");
            ServiceUtil.assertion(!signVerified, "验签失败");
        } catch (Exception e) {
            throw new ServiceException("验签失败" + e.getMessage());
        }
    }
}
