
package com.tmerclub.cloud.payment.manager;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayConstants;
import com.alipay.api.domain.*;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.internal.util.codec.Base64;
import com.alipay.api.request.*;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.github.binarywang.wxpay.bean.notify.*;
import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import com.github.binarywang.wxpay.bean.order.WxPayNativeOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryV3Result;
import com.github.binarywang.wxpay.bean.result.enums.TradeTypeEnum;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.tmerclub.cloud.api.payment.constant.PaySysType;
import com.tmerclub.cloud.api.platform.config.FeignShopConfig;
import com.tmerclub.cloud.api.platform.feign.ConfigFeignClient;
import com.tmerclub.cloud.api.user.bo.BalancePayBO;
import com.tmerclub.cloud.api.user.bo.BalanceRefundBO;
import com.tmerclub.cloud.api.user.feign.UserBalanceLogFeignClient;
import com.tmerclub.cloud.common.bean.Alipay;
import com.tmerclub.cloud.common.bean.WxPay;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.PayType;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.util.IpHelper;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.common.util.PriceUtil;
import com.tmerclub.cloud.payment.allinpay.bean.OpenRequest;
import com.tmerclub.cloud.payment.allinpay.member.resp.AllinpayResp;
import com.tmerclub.cloud.payment.allinpay.order.resp.GetOrderStatusResp;
import com.tmerclub.cloud.payment.bo.PayInfoBO;
import com.tmerclub.cloud.payment.bo.PayInfoResultBO;
import com.tmerclub.cloud.payment.bo.RefundInfoBO;
import com.tmerclub.cloud.payment.bo.RefundInfoResultBO;
import com.tmerclub.cloud.payment.config.AliPayConfig;
import com.tmerclub.cloud.payment.config.AllinpayConfig;
import com.tmerclub.cloud.payment.config.WxConfig;
import com.tmerclub.cloud.payment.model.PayInfo;
import com.tmerclub.cloud.payment.service.PayInfoService;
import com.tmerclub.cloud.payment.vo.PaySettlementConfigVO;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.constraints.NotNull;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * 统一支付工具
 *
 * @author tmerclub
 */
@Service
public class PayManager {

    @Autowired
    private AliPayConfig aliPayConfig;

    @Autowired
    private FeignShopConfig feignShopConfig;

    @Autowired
    private WxConfig wxConfig;

    @Autowired
    private PayInfoService payInfoService;

    @Autowired
    private PayNoticeManager payNoticeManager;
    @DubboReference
    private UserBalanceLogFeignClient userBalanceLogFeignClient;
    @DubboReference
    private ConfigFeignClient configFeignClient;
    @Autowired
    private AllinpayManager allinpayPayManager;
    @Autowired
    private AllinpayConfig allinpayConfig;

    private static final String WX_SUCCESS_XML = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>";
    private static final String ALI_SUCCESS = "success";
    public static final String SUCCESS = "SUCCESS";
    private static final String TRADE_SUCCESS = "TRADE_SUCCESS";
    private static final String TRADE_CLOSED = "TRADE_CLOSED";
    private static final String ALLINPAY_SUCCESS = "OK";
    private static final String TRADE_STATUS_KEY = "trade_status";
    private static final String REFUND = "refund_fee";
    private static final String REFUND_SUCCESS = "REFUND_SUCCESS";
    private static final String GMT_CLOSE = "gmt_close";
    private static final Long ALLINPAY_ORDER_SUCCESS = 4L;
    private static final Logger logger = LoggerFactory.getLogger(PayManager.class);

    public ServerResponseEntity<?> doPay(PayInfoBO payInfo) throws WxPayException, AlipayApiException {
        ServerResponseEntity<String> configResponse = configFeignClient.getConfig(Constant.PAY_SETTLEMENT_CONFIG);
        if (!configResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        PaySettlementConfigVO paySettlementConfigVO = Json.parseObject(configResponse.getData(), PaySettlementConfigVO.class);
        PayType payType = PayType.instance(payInfo.getPayType());
        // 积分支付
        if (Objects.equals(payType, PayType.SCOREPAY)) {
            PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
            payInfoResultBO.setPaySuccess(true);
            payInfoResultBO.setPayId(payInfo.getPayId());
            payInfoResultBO.setCallbackContent("余额支付成功");
            payInfoResultBO.setPayAmount(payInfo.getPayAmount());
            payInfoResultBO.setBizPayNo(payInfo.getPayId().toString());
            payNoticeManager.noticeOrder(payInfoResultBO, payInfoService.getByPayId(payInfo.getPayId()), paySettlementConfigVO.getPaySettlementType());
            return null;
        }
        if (Objects.equals(paySettlementConfigVO.getPaySettlementType(), 0)) {
            return doOriginalPay(payInfo);
        }
        return allinpayPayManager.doAllinPay(payInfo);
    }


    private ServerResponseEntity<?> doOriginalPay(PayInfoBO payInfo) throws WxPayException, AlipayApiException {
        String notifyUrl = payInfo.getApiNoticeUrl();

        PayType payType = PayType.instance(payInfo.getPayType());
        if (isWxPay(payType)) {
            Integer wxPayVersion = feignShopConfig.getWxPay().getVersion();
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                return doWxPayV3(payInfo, notifyUrl, payType);
            } else {
                return doWxPay(payInfo, notifyUrl, payType);
            }
        } else if (Objects.equals(payType, PayType.ALIPAY)) {
            //创建API对应的request
            AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();

            //在公共参数中设置回跳和通知地址
            alipayRequest.setNotifyUrl(notifyUrl);
            alipayRequest.setReturnUrl(payInfo.getReturnUrl());
            AlipayTradePagePayModel alipayTradePagePayModel = new AlipayTradePagePayModel();
            alipayTradePagePayModel.setOutTradeNo(String.valueOf(payInfo.getPayId()));
            alipayTradePagePayModel.setBody(payInfo.getBody());
            alipayTradePagePayModel.setSubject(payInfo.getBody());
            alipayTradePagePayModel.setTotalAmount(PriceUtil.toDecimalPrice(payInfo.getPayAmount()).toString());
            alipayTradePagePayModel.setProductCode("FAST_INSTANT_TRADE_PAY");
            alipayRequest.setBizModel(alipayTradePagePayModel);

            return ServerResponseEntity.success(aliPayConfig.getAlipayClient().pageExecute(alipayRequest).getBody());
        } else if (Objects.equals(payType, PayType.ALIPAY_H5)) {

            AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
            alipayRequest.setNotifyUrl(notifyUrl);
            alipayRequest.setReturnUrl(payInfo.getReturnUrl());

            AlipayTradeWapPayModel alipayTradeWapPayModel = new AlipayTradeWapPayModel();
            alipayTradeWapPayModel.setOutTradeNo(String.valueOf(payInfo.getPayId()));
            alipayTradeWapPayModel.setSubject(payInfo.getBody());
            alipayTradeWapPayModel.setTotalAmount(PriceUtil.toDecimalPrice(payInfo.getPayAmount()).toString());
            alipayTradeWapPayModel.setProductCode("QUICK_WAP_PAY");
            alipayRequest.setBizModel(alipayTradeWapPayModel);
            return ServerResponseEntity.success(aliPayConfig.getAlipayClient().pageExecute(alipayRequest).getBody());
        }
        // 支付宝app支付
        else if (Objects.equals(payType, PayType.ALIPAY_APP)) {

            AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest();
            alipayRequest.setNotifyUrl(notifyUrl);
            AlipayTradeAppPayModel alipayTradeAppPayModel = new AlipayTradeAppPayModel();
            alipayTradeAppPayModel.setOutTradeNo(String.valueOf(payInfo.getPayId()));
            alipayTradeAppPayModel.setSubject(payInfo.getBody());
            alipayTradeAppPayModel.setTotalAmount(PriceUtil.toDecimalPrice(payInfo.getPayAmount()).toString());
            alipayTradeAppPayModel.setProductCode("QUICK_MSECURITY_PAY");
            alipayRequest.setBizModel(alipayTradeAppPayModel);

            String body = aliPayConfig.getAlipayClient().sdkExecute(alipayRequest).getBody();
            return ServerResponseEntity.success(body);
        } else if (Objects.equals(payType, PayType.BALANCE)) {
            // 创建余额支付记录
            BalancePayBO balancePayBO = new BalancePayBO();
            balancePayBO.setOrderIds(payInfo.getOrderIds());
            balancePayBO.setChangeBalance(payInfo.getPayAmount());
            balancePayBO.setPayId(payInfo.getPayId());
            if (Objects.nonNull(payInfo.getIsVip())) {
                balancePayBO.setIsVip(payInfo.getIsVip());
            } else {
                balancePayBO.setIsVip(false);
            }
            balancePayBO.setPaySysType(PaySysType.DEFAULT.value());
            ServerResponseEntity<Void> insertServerResponseEntity = userBalanceLogFeignClient.insertBalancePayLog(balancePayBO);
            if (!insertServerResponseEntity.isSuccess()) {
                return ServerResponseEntity.transform(insertServerResponseEntity);
            }
            return ServerResponseEntity.success(payInfo.getPayId());
        }
        return null;
    }


    private ServerResponseEntity<?> doWxPay(PayInfoBO payInfo, String notifyUrl, PayType payType) throws WxPayException {
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
        orderRequest.setBody(payInfo.getBody());
        orderRequest.setOutTradeNo(String.valueOf(payInfo.getPayId()));
        orderRequest.setTotalFee((int) (long) payInfo.getPayAmount());
        orderRequest.setSpbillCreateIp(IpHelper.getIpAddr());
        orderRequest.setOpenid(payInfo.getBizUserId());

        orderRequest.setNotifyUrl(notifyUrl);

        if (payInfo.getPayAmount() > Constant.MAX_WECHA_TPAY_AMOUNT) {
            throw new LuckException("已超出微信支付的最大金额，请选择其他付款方式");
        }

        // 微信小程序支付 || 微信公众号支付
        if (Objects.equals(payType, PayType.WECHATPAY) || Objects.equals(payType, PayType.WECHATPAY_MP)) {
            orderRequest.setTradeType(WxPayConstants.TradeType.JSAPI);
            WxPayMpOrderResult wxPayMpOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayMpOrderResult);
        }
        // 微信网页支付
        else if (Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)) {
            orderRequest.setProductId(String.valueOf(payInfo.getPayId()));
            // 生成微信二维码
            orderRequest.setTradeType(WxPayConstants.TradeType.NATIVE);
            WxPayNativeOrderResult wxPayNativeOrderResult = wxPayService.createOrder(orderRequest);

            return ServerResponseEntity.success(wxPayNativeOrderResult.getCodeUrl());
        }
        // 微信H5支付
        else if (Objects.equals(payType, PayType.WECHATPAY_H5)) {
            // 生成微信二维码
            orderRequest.setTradeType(WxPayConstants.TradeType.MWEB);
            String s = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"\",\"wap_name\": \"\"}}";
            orderRequest.setSceneInfo(s);
            WxPayMwebOrderResult wxPayMwebOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayMwebOrderResult.getMwebUrl());
        }
        // 微信app支付
        else if (Objects.equals(payType, PayType.WECHATPAY_APP)) {
            orderRequest.setTradeType(WxPayConstants.TradeType.APP);
            WxPayAppOrderResult wxPayAppOrderResult = wxPayService.createOrder(orderRequest);
            return ServerResponseEntity.success(wxPayAppOrderResult);
        }
        return null;
    }

    private ServerResponseEntity<?> doWxPayV3(PayInfoBO payInfo, String notifyUrl, PayType payType) throws WxPayException {
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        WxPayUnifiedOrderV3Request orderRequest = new WxPayUnifiedOrderV3Request();
        orderRequest.setDescription(payInfo.getBody());
        orderRequest.setOutTradeNo(payInfo.getPayId().toString());
        orderRequest.setNotifyUrl(notifyUrl);
        orderRequest.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(Integer.parseInt(payInfo.getPayAmount().toString())));

        // 微信小程序支付 || 微信公众号支付
        if (Objects.equals(payType, PayType.WECHATPAY) || Objects.equals(payType, PayType.WECHATPAY_MP)) {
            orderRequest.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid(payInfo.getBizUserId()));
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.JSAPI, orderRequest));
        }
        // 微信网页支付
        else if (Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)) {
            // 生成微信二维码
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.NATIVE, orderRequest));
        }
        // 微信H5支付
        else if (Objects.equals(payType, PayType.WECHATPAY_H5)) {
            orderRequest.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo()
                    .setPayerClientIp(IpHelper.getIpAddr())
                    .setH5Info(new WxPayUnifiedOrderV3Request.H5Info().setType("Wap")));
            // 生成h5支付地址
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.H5, orderRequest));
        }
        // 微信app支付
        else if (Objects.equals(payType, PayType.WECHATPAY_APP)) {
            return ServerResponseEntity.success(wxPayService.createOrderV3(TradeTypeEnum.APP, orderRequest));
        }
        return null;
    }

    public PayInfoResultBO validateAndGetPayInfo(Integer paySysType, HttpServletRequest request, PayType payType, String data) throws UnsupportedEncodingException, WxPayException, AlipayApiException {
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            logger.info("通联支付回调开始,回调内容为{}", request.getParameterMap().toString());
            // 通联回调校验
            return validateAllinpay(data, request);
        }

        PayInfoResultBO payInfoBo = new PayInfoResultBO();
        // 微信支付
        if (isWxPay(payType)) {
            WxPayService wxPayService = wxConfig.getWxPayService(payType);
            Integer wxPayVersion = feignShopConfig.getWxPay().getVersion();
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                WxPayNotifyV3Result wxPayOrderNotifyV3Result = wxPayService.parseOrderNotifyV3Result(data, getSignatureHeader(request));
                payInfoBo.setPayId(Long.valueOf(wxPayOrderNotifyV3Result.getResult().getOutTradeNo()));
                payInfoBo.setBizPayNo(wxPayOrderNotifyV3Result.getResult().getTransactionId());
                payInfoBo.setPaySuccess(SUCCESS.equals(wxPayOrderNotifyV3Result.getResult().getTradeState()));
                payInfoBo.setPayAmount(Long.valueOf(wxPayOrderNotifyV3Result.getResult().getAmount().getTotal()));
                payInfoBo.setCallbackContent(data);
            } else {
                WxPayOrderNotifyResult parseOrderNotifyResult = wxPayService.parseOrderNotifyResult(data);
                payInfoBo.setPayId(Long.valueOf(parseOrderNotifyResult.getOutTradeNo()));
                payInfoBo.setBizPayNo(parseOrderNotifyResult.getTransactionId());
                payInfoBo.setPaySuccess(SUCCESS.equals(parseOrderNotifyResult.getResultCode()));
                payInfoBo.setSuccessString(WX_SUCCESS_XML);
                payInfoBo.setPayAmount(Long.valueOf(parseOrderNotifyResult.getTotalFee()));
                payInfoBo.setCallbackContent(data);
            }
        } else if (isAliPay(payType)) {
            //获取支付宝POST过来反馈信息
            Map<String, String> params = parseAliNotifyAndGetResult(request);
            //商户订单号,之前生成的带用户ID的订单号
            payInfoBo.setPayId(Long.valueOf(params.get("out_trade_no")));
            //支付宝交易号
            payInfoBo.setBizPayNo(params.get("trade_no"));
            payInfoBo.setSuccessString(ALI_SUCCESS);
            payInfoBo.setPayAmount(new BigDecimal(params.get("total_amount")).multiply(new BigDecimal(100)).longValue());
            // 这个不是支付宝退款的通知
            if (StrUtil.isBlank(params.get(REFUND))) {
                payInfoBo.setPaySuccess(Objects.equals(params.get(TRADE_STATUS_KEY), TRADE_SUCCESS));
            } else {
                // 支付宝退款回调
                boolean isAliAllRefund = Objects.equals(params.get(TRADE_STATUS_KEY), TRADE_CLOSED) && StrUtil.isNotBlank(params.get(GMT_CLOSE));
                if (Objects.equals(params.get(TRADE_STATUS_KEY), TRADE_SUCCESS) || isAliAllRefund) {
                    payInfoBo.setPaySuccess(true);
                    payInfoBo.setIsAliRefund(true);
                    payInfoBo.setRefundId(Long.valueOf(params.get("out_biz_no")));
                    payInfoBo.setCallbackContent(Json.toJsonString(params));
                } else {
                    payInfoBo.setPaySuccess(false);
                }
            }

            payInfoBo.setCallbackContent(Json.toJsonString(params));
        }

        if (StrUtil.isNotBlank(payInfoBo.getCallbackContent())) {
            PayInfo payInfo = new PayInfo();
            payInfo.setPayId(payInfoBo.getPayId());
            payInfo.setBizPayNo(payInfoBo.getBizPayNo());
            payInfo.setCallbackContent(payInfoBo.getCallbackContent());
            payInfo.setCallbackTime(new Date());
            payInfoService.update(payInfo);
        }
        return payInfoBo;
    }

    private PayInfoResultBO validateAllinpay(String data, HttpServletRequest request) throws UnsupportedEncodingException {
        // 验签
        OpenRequest openRequest = allinpayConfig.validateAllinpayAndReturn(data, request);
        // 2.转换成bean
        AllinpayResp allinpayResp = JSON.parseObject(openRequest.getBizContent(), AllinpayResp.class);
        PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
        payInfoResultBO.setPayId(Long.valueOf(allinpayResp.getBizOrderNo()));
        payInfoResultBO.setBizPayNo(allinpayResp.getOrderNo());
        payInfoResultBO.setPaySuccess(Objects.equals(allinpayResp.getStatus(), ALLINPAY_SUCCESS));
        payInfoResultBO.setSuccessString(ALLINPAY_SUCCESS);
        payInfoResultBO.setPayAmount(allinpayResp.getAmount());
        payInfoResultBO.setCallbackContent(openRequest.getBizContent());
        payInfoResultBO.setPaySysType(PaySysType.ALLINPAY.value());
        payInfoResultBO.setExtendInfo(allinpayResp.getExtendInfo());
        // 修改支付信息
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payInfoResultBO.getPayId());
        payInfo.setBizPayNo(payInfoResultBO.getBizPayNo());
        payInfo.setCallbackContent(Json.toJsonString(openRequest.getBizContent()));
        payInfo.setCallbackTime(new Date());
        payInfoService.update(payInfo);
        return payInfoResultBO;
    }

    private RefundInfoResultBO validateRefundAllinpay(String data, HttpServletRequest request) throws UnsupportedEncodingException {
        RefundInfoResultBO refundInfoResultBo = new RefundInfoResultBO();
        //获取支付宝POST过来反馈信息
        Map<String, String> params = allinpayConfig.getParams(request);
        logger.info("data:{}", data);

        if (!allinpayConfig.signVerify(params)) {
            // 验签失败
            refundInfoResultBo.setRefundSuccess(false);
            return refundInfoResultBo;
        }
        String paramsStr = JSON.toJSONString(params);
        OpenRequest openRequest = JSONObject.parseObject(paramsStr, OpenRequest.class);
        // 2.转换成bean
        AllinpayResp allinpayResp = JSON.parseObject(openRequest.getBizContent(), AllinpayResp.class);


        refundInfoResultBo.setRefundSuccess(ALLINPAY_SUCCESS.equals(allinpayResp.getStatus()));
        refundInfoResultBo.setSuccessString(WX_SUCCESS_XML);
        // 处理下预售订单退款的退款号
        String[] bizOrderNumbers = allinpayResp.getBizOrderNo().split(StrUtil.UNDERLINE);
        refundInfoResultBo.setRefundId(Long.valueOf(bizOrderNumbers[0]));
        refundInfoResultBo.setBizRefundNo(allinpayResp.getOrderNo());
        refundInfoResultBo.setCallbackContent(data);
        return refundInfoResultBo;
    }

    @NotNull
    private SignatureHeader getSignatureHeader(HttpServletRequest request) {
        SignatureHeader signatureHeader = new SignatureHeader();
        signatureHeader.setSignature(request.getHeader("Wechatpay-Signature"));
        signatureHeader.setNonce(request.getHeader("Wechatpay-Nonce"));
        signatureHeader.setTimeStamp(request.getHeader("Wechatpay-TimeStamp"));
        signatureHeader.setSerial(request.getHeader("Wechatpay-Serial"));
        return signatureHeader;
    }

    public boolean doRefund(RefundInfoBO refundInfo) {
        PayType payType = refundInfo.getPayType();
        if (Objects.equals(refundInfo.getRefundAmount(), 0L)) {
            return true;
        }
        // 提交提款操作
        try {
            if (isWxPay(payType)) {
                handleWxRefund(refundInfo, payType);
            } else if (isAliPay(payType)) {
                AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
                AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
                alipayTradeRefundModel.setOutTradeNo(refundInfo.getPayId().toString());
                alipayTradeRefundModel.setRefundAmount(PriceUtil.toDecimalPrice(refundInfo.getRefundAmount()).toString());
                alipayTradeRefundModel.setOutRequestNo(refundInfo.getRefundId().toString());
                request.setBizModel(alipayTradeRefundModel);
                AlipayTradeRefundResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                // 支付宝使用回调验证退款，回调地址为支付的时候填的回调地址，支付宝电脑支付全额退款没有回调，通过定时任务updateAliPayRefundStatus处理
                if (!response.isSuccess()) {
                    logger.error("退款失败，Mq会多次回调：{}", Json.toJsonString(response));
                    // 因为这个退款是mq调用的，所以如果一次退款失败，就调用多次，做好幂等的操作
                    throw new LuckException(ResponseEnum.EXCEPTION);
                }
            } else if (Objects.equals(payType, PayType.BALANCE)) {
                // 注意 只进行退款是不需要回调的 这个参数要传到余额支付那，不然会有问题
                // 退款金额
                BalanceRefundBO balanceRefundBO = new BalanceRefundBO();
                balanceRefundBO.setRefundId(refundInfo.getRefundId());
                balanceRefundBO.setPayId(refundInfo.getPayId());
                balanceRefundBO.setChangeBalance(refundInfo.getRefundAmount());
                balanceRefundBO.setUserId(refundInfo.getUserId());
                balanceRefundBO.setRefundNumber(refundInfo.getRefundNumber());
                balanceRefundBO.setPaySysType(PaySysType.DEFAULT.value());
                ServerResponseEntity<Void> responseEntity = userBalanceLogFeignClient.doRefund(balanceRefundBO);
                if (responseEntity.isSuccess()) {
                    return true;
                } else {
                    logger.error("退款失败，Mq会多次回调：{}", Json.toJsonString(responseEntity));
                    // 因为这个退款是mq调用的，所以如果一次退款失败，就调用多次，做好幂等的操作
                    throw new LuckException(ResponseEnum.EXCEPTION);
                }
            }
        } catch (WxPayException e) {
            logger.error("异常", e);
            throw new LuckException(e.getCustomErrorMsg(), e);
        } catch (AlipayApiException e) {
            logger.error("异常", e);
            throw new LuckException(e.getErrMsg(), e);
        }
        return false;
    }

    private void handleWxRefund(RefundInfoBO refundInfo, PayType payType) throws WxPayException {
        // 订单金额
        int totalFee = Integer.parseInt(refundInfo.getPayAmount().toString());
        // 退款金额
        int refundFee = Integer.parseInt(refundInfo.getRefundAmount().toString());
        WxPayService wxPayService = wxConfig.getWxPayService(payType);
        Integer wxPayVersion = feignShopConfig.getWxPay().getVersion();
        if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
            WxPayRefundV3Request wxPayRefundV3Request = new WxPayRefundV3Request();
            wxPayRefundV3Request.setOutTradeNo(refundInfo.getPayId().toString());
            wxPayRefundV3Request.setAmount(new WxPayRefundV3Request.Amount().setTotal(totalFee).setRefund(refundFee).setCurrency("CNY"));
            wxPayRefundV3Request.setOutRefundNo(refundInfo.getRefundId().toString());
            // notifyUrl（通知结果）
            if (!Objects.equals(refundInfo.getOnlyRefund(), 1)) {
                // 只进行退款，不需要任何回调
                wxPayRefundV3Request.setNotifyUrl(refundInfo.getNotifyUrl());
            }
            wxPayService.refundV3(wxPayRefundV3Request);
        } else {
            // 退款操作
            // 生成退款请求对象
            WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
            // 商户订单号
            wxPayRefundRequest.setOutTradeNo(refundInfo.getPayId().toString());
            // 订单金额
            wxPayRefundRequest.setTotalFee(refundInfo.getPayAmount().intValue());
            // 退款金额
            wxPayRefundRequest.setRefundFee(refundInfo.getRefundAmount().intValue());
            // 退款编码
            wxPayRefundRequest.setOutRefundNo(refundInfo.getRefundId().toString());

            // 只进行退款，不需要任何回调
            if (!Objects.equals(refundInfo.getOnlyRefund(), 1)) {
                // notifyUrl（通知结果）
                wxPayRefundRequest.setNotifyUrl(refundInfo.getNotifyUrl());
            }
            wxPayService.refund(wxPayRefundRequest);
        }
    }

    public RefundInfoResultBO validateAndGetRefundInfo(HttpServletRequest request, Integer paySysType, PayType payType, String data) throws WxPayException, UnsupportedEncodingException {
        if (Objects.equals(paySysType, PaySysType.ALLINPAY.value())) {
            // 通联回调校验
            return validateRefundAllinpay(data, request);
        }
        RefundInfoResultBO refundInfoResultBo = new RefundInfoResultBO();
        refundInfoResultBo.setRefundSuccess(false);

        if (isWxPay(payType)) {
            Integer wxPayVersion = feignShopConfig.getWxPay().getVersion();
            WxPayService wxPayService = wxConfig.getWxPayService(payType);
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                WxPayRefundNotifyV3Result wxPayRefundNotifyV3Result = wxPayService.parseRefundNotifyV3Result(data, getSignatureHeader(request));
                WxPayRefundNotifyV3Result.DecryptNotifyResult result = wxPayRefundNotifyV3Result.getResult();
                if (Constant.SUCCESS.equals(result.getRefundStatus())) {
                    refundInfoResultBo.setRefundSuccess(SUCCESS.equals(result.getRefundStatus()));
                    refundInfoResultBo.setSuccessString(WX_SUCCESS_XML);
                    refundInfoResultBo.setRefundId(Long.valueOf(result.getOutRefundNo()));
                    refundInfoResultBo.setBizRefundNo(result.getRefundId());
                    refundInfoResultBo.setCallbackContent(data);
                }
            } else {
                WxPayRefundNotifyResult wxPayRefundNotifyResult = wxConfig.getWxPayService(payType).parseRefundNotifyResult(data);
                WxPayRefundNotifyResult.ReqInfo reqInfo = wxPayRefundNotifyResult.getReqInfo();
                if (Constant.SUCCESS.equals(reqInfo.getRefundStatus())) {
                    refundInfoResultBo.setRefundId(Long.valueOf(reqInfo.getOutRefundNo()));
                    refundInfoResultBo.setRefundSuccess(SUCCESS.equals(reqInfo.getRefundStatus()));
                    refundInfoResultBo.setSuccessString(WX_SUCCESS_XML);
                    refundInfoResultBo.setBizRefundNo(reqInfo.getRefundId());
                    refundInfoResultBo.setCallbackContent(data);
                }
            }
        }
        return refundInfoResultBo;
    }

    /**
     * 获取支付宝POST过来反馈信息
     */
    private Map<String, String> parseAliNotifyAndGetResult(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
        //乱码解决，这段代码在出现乱码时使用
        request.setCharacterEncoding("utf-8");
        //获取支付宝POST过来反馈信息
        Map<String, String> params = allinpayConfig.getParams(request);
        //调用SDK验证签名
        boolean signVerified;
        Alipay alipay = feignShopConfig.getAlipay();
        if (StrUtil.isBlank(alipay.getAlipayCertContent())) {
            signVerified = AlipaySignature.rsaCertCheckV1(params, alipay.getAlipayCertPath(), cn.hutool.core.util.CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
        } else {
            String publicKey;
            try {
                publicKey = this.getPublicKeyByContent(alipay.getAlipayCertContent());
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            signVerified = AlipaySignature.rsaCheckV1(params, publicKey, cn.hutool.core.util.CharsetUtil.UTF_8, AlipayConstants.SIGN_TYPE_RSA2);
        }
        if (!signVerified) {
            // 验签失败
            throw new LuckException("验签失败");
        }
        return params;
    }


    public boolean isWxPay(PayType payType) {
        return (Objects.equals(payType, PayType.WECHATPAY)
                || Objects.equals(payType, PayType.WECHATPAY_SWEEP_CODE)
                || Objects.equals(payType, PayType.WECHATPAY_H5)
                || Objects.equals(payType, PayType.WECHATPAY_MP)
                || Objects.equals(payType, PayType.WECHATPAY_APP));
    }

    public boolean isAliPay(PayType payType) {
        return (Objects.equals(payType, PayType.ALIPAY_H5)
                || Objects.equals(payType, PayType.ALIPAY)
                || Objects.equals(payType, PayType.ALIPAY_APP));
    }

    public PayInfoResultBO checkPaySuccess(PayInfo payInfo) {
        PayInfoResultBO payInfoResultBO = new PayInfoResultBO();
        payInfoResultBO.setPayId(payInfo.getPayId());
        payInfoResultBO.setPayAmount(payInfo.getPayAmount());
        payInfoResultBO.setBizPayNo(payInfo.getBizPayNo());
        PayType payType = PayType.instance(payInfo.getPayType());
        String payId = String.valueOf(payInfo.getPayId());
        try {
            if(Objects.equals(payInfo.getPaySysType(),PaySysType.ALLINPAY.value())){
                GetOrderStatusResp orderStatusResp = allinpayPayManager.getOrderStatus(payInfo.getPayId().toString());
                payInfoResultBO.setPaySuccess(Boolean.FALSE);
                if(Objects.nonNull(orderStatusResp) && Objects.equals(orderStatusResp.getOrderStatus(),ALLINPAY_ORDER_SUCCESS)) {
                    payInfoResultBO.setBizPayNo(orderStatusResp.getOrderNo());
                    payInfoResultBO.setPaySuccess(Boolean.TRUE);
                }
                return payInfoResultBO;
            }
            if (PayType.isWeChatPay(payInfo.getPayType())) {
                WxPayService wxPayService = wxConfig.getWxPayService(payType);
                WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, payId);
                if (!Objects.isNull(wxPayOrderQueryResult) && Objects.equals(wxPayOrderQueryResult.getTradeState(), Constant.SUCCESS)) {
                    payInfoResultBO.setBizPayNo(wxPayOrderQueryResult.getTransactionId());
                    payInfoResultBO.setPaySuccess(Boolean.TRUE);
                } else {
                    payInfoResultBO.setPaySuccess(Boolean.FALSE);
                }
            } else if (PayType.isAliPay(payInfo.getPayType())) {
                AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
                AlipayTradeQueryModel alipayTradeQueryModel = new AlipayTradeQueryModel();
                alipayTradeQueryModel.setOutTradeNo(payId);

                request.setBizModel(alipayTradeQueryModel);
                AlipayTradeQueryResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                if (response.isSuccess() && Objects.equals(response.getTradeStatus(), TRADE_SUCCESS)) {
                    payInfoResultBO.setBizPayNo(response.getTradeNo());
                    payInfoResultBO.setPaySuccess(Boolean.TRUE);
                } else {
                    payInfoResultBO.setPaySuccess(Boolean.FALSE);
                }
            } else if (Objects.equals(payInfo.getPayType(), PayType.BALANCE.value())) {
                // 如果是余额支付，且订单是待支付状态，直接返回false取消订单
                payInfoResultBO.setPaySuccess(Boolean.FALSE);
            }
        } catch (WxPayException | AlipayApiException e) {
            logger.error("获取支付信息错误：", e);
        }
        return payInfoResultBO;
    }

    public void cancelOrderQrCode(Long payId, Integer payType) throws WxPayException, AlipayApiException {
        Integer wxPayVersion = feignShopConfig.getWxPay().getVersion();
        PayType type = PayType.instance(payType);
        if (isWxPay(type)) {
            WxPayService wxPayService = wxConfig.getWxPayService(type);
            // v3需要的配置
            if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                wxPayService.closeOrderV3(payId.toString());
            } else {
                wxPayService.closeOrder(payId.toString());
            }
        }else{
            AlipayTradeCloseRequest tradeCloseRequest = new AlipayTradeCloseRequest();
            AlipayTradeCloseModel tradeCloseModel = new AlipayTradeCloseModel();
            tradeCloseModel.setOutTradeNo(payId.toString());
            tradeCloseRequest.setBizModel(tradeCloseModel);
            aliPayConfig.getAlipayClient().certificateExecute(tradeCloseRequest);
        }
    }

    private String getPublicKeyByContent(String content) throws Exception{
        InputStream inputStream = new ByteArrayInputStream(content.getBytes());
        CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
        X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
        PublicKey publicKey = cert.getPublicKey();
        return Base64.encodeBase64String(publicKey.getEncoded());
    }

    /**
     * 获取退款信息
     */
    public RefundInfoResultBO getRefundInfo(Integer payType, Long payId, Integer paySysType, Long refundId) {
        RefundInfoResultBO refundInfoBo = new RefundInfoResultBO();
        refundInfoBo.setRefundId(refundId);
        if(Objects.equals(paySysType,PaySysType.ALLINPAY.value())){
            GetOrderStatusResp orderStatusResp = allinpayPayManager.getOrderStatus(refundId + StrUtil.UNDERLINE + 1);
            refundInfoBo.setRefundSuccess(false);
            if(Objects.nonNull(orderStatusResp) && Objects.equals(orderStatusResp.getOrderStatus(),ALLINPAY_ORDER_SUCCESS)) {
                refundInfoBo.setBizRefundNo(orderStatusResp.getOrderNo());
                refundInfoBo.setRefundSuccess(true);
            }
            // 预售可能有两笔退款,两笔退款成功即可
            GetOrderStatusResp getOrderStatusResp = allinpayPayManager.getOrderStatus(refundId + StrUtil.UNDERLINE + 2);
            // 不为空就是有退款,则判断是否成功
            if(Objects.nonNull(getOrderStatusResp)){
                refundInfoBo.setRefundSuccess(false);
                if(Objects.equals(getOrderStatusResp.getOrderStatus(),ALLINPAY_ORDER_SUCCESS)) {
                    refundInfoBo.setRefundSuccess(true);
                }
            }
            return refundInfoBo;
        }
        try {
            if (PayType.isWeChatPay(payType)) {
                Integer wxPayVersion = feignShopConfig.getWxPay().getVersion();
                PayType type = PayType.instance(payType);
                WxPayService wxPayService = wxConfig.getWxPayService(type);
                // v3需要的配置
                if (Objects.equals(WxPay.VERSION_3, wxPayVersion)) {
                    WxPayRefundQueryV3Result wxPayRefundQueryV3Result = wxPayService.refundQueryV3(refundId.toString());
                    if (Objects.nonNull(wxPayRefundQueryV3Result) && Objects.equals(wxPayRefundQueryV3Result.getStatus(), Constant.SUCCESS)) {
                        refundInfoBo.setBizRefundNo(wxPayRefundQueryV3Result.getRefundId());
                        refundInfoBo.setRefundSuccess(true);
                    } else {
                        refundInfoBo.setRefundSuccess(false);
                    }
                } else {
                    WxPayRefundQueryResult wxPayRefundQueryResult = wxPayService.refundQuery(null, null, refundId.toString(), null);
                    if (Objects.isNull(wxPayRefundQueryResult) || CollUtil.isEmpty(wxPayRefundQueryResult.getRefundRecords())) {
                        refundInfoBo.setRefundSuccess(false);
                    } else {
                        WxPayRefundQueryResult.RefundRecord refundRecord = wxPayRefundQueryResult.getRefundRecords().get(0);
                        if (Objects.equals(refundRecord.getRefundStatus(), Constant.SUCCESS)) {
                            refundInfoBo.setBizRefundNo(refundRecord.getRefundId());
                            refundInfoBo.setRefundSuccess(true);
                        } else {
                            refundInfoBo.setRefundSuccess(false);
                        }
                    }
                }
            } else if (PayType.isAliPay(payType)) {
                AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
                AlipayTradeFastpayRefundQueryModel alipayTradeFastpayRefundQueryModel = new AlipayTradeFastpayRefundQueryModel();
                alipayTradeFastpayRefundQueryModel.setOutTradeNo(payId.toString());
                alipayTradeFastpayRefundQueryModel.setOutRequestNo(refundId.toString());
                request.setBizModel(alipayTradeFastpayRefundQueryModel);
                AlipayTradeFastpayRefundQueryResponse response = aliPayConfig.getAlipayClient().certificateExecute(request);
                if (response.isSuccess() && Objects.equals(response.getRefundStatus(), REFUND_SUCCESS)) {
                    refundInfoBo.setBizRefundNo(response.getTradeNo());
                    refundInfoBo.setRefundSuccess(true);
                } else {
                    refundInfoBo.setRefundSuccess(false);
                }
            } else {
                refundInfoBo.setRefundSuccess(false);
            }
        } catch (WxPayException | AlipayApiException e) {
            logger.error("获取退款信息错误：", e);
            refundInfoBo.setRefundSuccess(false);
        }
        return refundInfoBo;
    }
}
