package com.ruoyi.ss.callback.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.pay.wx.domain.NotifyEventType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.ss.callback.domain.CallbackLog;
import com.ruoyi.ss.callback.mapper.CallbackLogMapper;
import com.ruoyi.ss.callback.service.ICallbackService;
import com.ruoyi.ss.changeBalance.service.IChangeBalanceService;
import com.ruoyi.ss.channel.domain.ChannelVO;
import com.ruoyi.ss.channel.service.IChannelService;
import com.ruoyi.ss.dividendDetail.domain.DividendDetail;
import com.ruoyi.ss.dividendDetail.domain.DividendDetailVO;
import com.ruoyi.ss.dividendDetail.service.IDividendDetailService;
import com.ruoyi.ss.dividendRefund.domain.DividendRefund;
import com.ruoyi.ss.dividendRefund.service.DividendRefundConverter;
import com.ruoyi.ss.dividendRefund.service.DividendRefundService;
import com.ruoyi.ss.order.domain.Order;
import com.ruoyi.ss.order.domain.OrderVO;
import com.ruoyi.ss.order.service.IOrderService;
import com.ruoyi.ss.orderOper.service.IOrderOperService;
import com.ruoyi.ss.payBill.domain.PayBill;
import com.ruoyi.ss.payBill.domain.PayBillQuery;
import com.ruoyi.ss.payBill.domain.PayBillVO;
import com.ruoyi.ss.payBill.domain.enums.PayBillStatus;
import com.ruoyi.ss.payBill.service.PayBillService;
import com.ruoyi.ss.product.domain.ProductVO;
import com.ruoyi.ss.product.service.IProductService;
import com.ruoyi.ss.refund.domain.Refund;
import com.ruoyi.ss.refund.service.IRefundService;
import com.ruoyi.ss.user.domain.UserVO;
import com.ruoyi.ss.user.service.IUserService;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.Notification;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import com.wechat.pay.java.service.refund.model.Status;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static com.ruoyi.common.constant.ServiceConstants.*;


/**
 * 订单支付回调 CallbackService 实现类
 */
@Service
public class CallbackServiceImpl implements ICallbackService {

    private static final Logger logger = LoggerFactory.getLogger(CallbackServiceImpl.class);

    @Resource
    private IOrderService orderService;

    @Resource
    private IRefundService etRefundService;

    @Autowired
    private ScheduledExecutorService scheduledExecutorService;

    @Resource
    private CallbackLogMapper callbackLogMapper;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private IChannelService rlChannelService;

    @Autowired
    private IUserService userService;

    @Autowired
    private IChangeBalanceService changeBalanceService;

    @Resource
    private IDividendDetailService dividendDetailService;

    @Autowired
    private IOrderOperService orderOperService;

    @Autowired
    private PayBillService paymentService;

    @Autowired
    private IProductService productService;

    @Autowired
    private DividendRefundConverter dividendRefundConverter;

    @Autowired
    private DividendRefundService dividendRefundService;

    @Value("${ruoyi.isTest}")
    private boolean isTest;

    @Value("${ruoyi.privateKeyPath}")
    private String path;


    /**
     * 微信支付回调
     */
    @Override
    @Transactional
    public void weChat(HttpServletRequest request) {
        String body = HttpUtils.getBody(request);
        logger.info("【微信支付回调】接收对象（未验签） : {}", JSON.toJSONString(body));
        CallbackLog etCallbackLog = new CallbackLog();
        etCallbackLog.setBody2(body);
        etCallbackLog.setType("1");
        // 解析通知数据
        Notification notification = JSON.parseObject(body, Notification.class);

        //异步保存回调日志
        asynchronousSaveCallbackLog(etCallbackLog);

        // 支付成功通知
        if (NotifyEventType.TRANSACTION_SUCCESS.getValue().equals(notification.getEventType())) {
            // 验签、解密并转换成 Transaction
            Transaction transaction = checkAndParse(request, body, Transaction.class);
            if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
                // 充值成功后的业务处理
                etCallbackLog.setBody(JSON.toJSONString(transaction));
                businessHandle(transaction.getOutTradeNo(), ServiceConstants.PAY_TYPE_WX,DateUtils.toLocalDateTimeByISO(transaction.getSuccessTime()));//业务处理
            }
        }
    }

    /**
     * 支付成功后的业务处理
     *  1. 更改订单状态，订单到期时间修改，账变记录保存至订单
     *  2. 生成配送工单
     *  3. 生成账变记录
     */
    @Override
    public void businessHandle(String outTradeNo, String payType, LocalDateTime payTime) {
        PayBillVO payBillVO = paymentService.selectByPayNo(outTradeNo);
        ServiceUtil.assertion(!PayBillStatus.PAYING.getStatus().equals(payBillVO.getStatus()), "该支付订单不是正在支付的支付订单");

        OrderVO orderVO = orderService.selectRlOrderByOrderNo(payBillVO.getOrderNo());
        ServiceUtil.assertion(orderVO == null, "订单不存在");

        logger.info("【支付回调】订单信息 : {}", JSON.toJSONString(orderVO));

        /**
         *  1. 更新支付订单表，pay_bill
         2. 更新订单表的状态
         3. 更新分账表  分账金额、状态、实际支付金额
         4. 更新用户账变
         5. 订单履历
         */
        Boolean execute = transactionTemplate.execute(e -> {
            updateOrder(orderVO,payTime,payBillVO);
            logger.info("【支付回调】----------更新订单表成功----------");

            updatePayBill(payBillVO,payTime);
            logger.info("【支付回调】----------更新支付订单表成功----------");
            String orderNo = orderVO.getOrderNo();
            if(orderNo.startsWith(ORDER_TYPE_REORDER_PREFIX) ){// 续单 已xd开头的都是续单
                logger.info("【支付回调】----------续费订单----------开始处理业务");

                updateDividendAndChangeBalance(orderVO,payBillVO.getPayNo(),REORDER);
                logger.info("【支付回调-续单】----------更新分账表成功----------");

                // 结束原订单
                closeOriginalOrder(orderVO.getOriginalOrderNo());
            }else if (orderNo.startsWith(ORDER_TYPE_TEA_PREFIX) || orderNo.startsWith(ORDER_TYPE_MAHJONG_PREFIX) || orderNo.startsWith(ORDER_TYPE_BILLIARDS_PREFIX)){// 正常预定订单
                logger.info("【支付回调】----------预约订单----------开始处理业务");

                updateDividendAndChangeBalance(orderVO,payBillVO.getPayNo(),RESERVE);
                logger.info("【支付回调-预订单】----------更新分账表成功----------");

            }else if(orderVO.getOrderNo().startsWith(ServiceConstants.ORDER_TYPE_CONTAINER_PREFIX)){
                logger.info("【支付回调】----------商品订单----------开始处理业务");

                updateDividendAndChangeBalance(orderVO,payBillVO.getPayNo(),PRODUCT_ORDER);

                // 库存减一
                takeOutStock(orderVO);
                logger.info("【支付回调】----------商品订单----------更新库存成功----------");

            } else {
                throw new ServiceException("非法的订单类型");
            }
//            else if (orderVO.getOrderNo().startsWith(ServiceConstants.ORDER_TYPE_RECHARGE_PREFIX)) { // 充值订单
//                logger.info("【支付回调】----------充值订单----------开始处理业务");
//                /**
//                 *   删除用户余额记录，新建一条记录   更新用户余额  余额表
//                 *         产生用户账变
//                 *         产生商户账变
//                 *         更新商户余额和待结算金额
//                 *         充值金额、实际到账金额
//                 *         √订单履历
//                 *         */
//
//                // 用户账变
//                userChangeBalance(orderVO, payBillVO.getPayNo());
//
////                //  todo 商户账变
////                merchantChangeBalance(orderVO, payBillVO.getPayNo());
//
//            }
            createOrderOper(orderVO);
            logger.info("【支付回调】----------创建订单履历成功----------");
            logger.info("=================【微信支付回调】全部结束！！！！！==================");
            return Boolean.TRUE;
        });
        if(Boolean.FALSE.equals(execute))throw new ServiceException("微信支付回调失败");
    }

    private void takeOutStock(OrderVO orderVO) {
        ProductVO product = productService.selectProductByProductId(orderVO.getProductId());
        ServiceUtil.assertion(product == null, "商品不存在");
        int i = productService.updateProductStock(product.getProductId());
        ServiceUtil.assertion(i < 1, "库存不足");
    }

    private void userChangeBalance(OrderVO orderVO, String payNo) {
        UserVO user = userService.selectUserById(orderVO.getUserId());
        ServiceUtil.assertion(user == null, "充值用户不存在");
        /* 记录账变  */
        int i = changeBalanceService.generateChangeBalance(orderVO.getOrderNo(), payNo, ServiceConstants.FLOW_TYPE_INCOME,
                ServiceConstants.RECHARGE, orderVO.getPayFee(), user.getUserId(), user.getUserName(), user.getPhonenumber(),user.getUserType());
        ServiceUtil.assertion(i == 0, "更新记录账变失败");
    }

    private void createOrderOper(OrderVO orderVO) {
        String orderNo = orderVO.getOrderNo();
        BigDecimal payFee = orderVO.getPayFee();
        Long userId = orderVO.getUserId();
        String phone = orderVO.getPhone();
        String status = orderVO.getStatus();
        String desc = getDesc(orderNo, payFee);
        recordOrderHistory(orderNo, status, status, payFee, userId, phone, desc);
    }

    private String getDesc(String orderNo, BigDecimal payFee) {
        String desc;
        // 使用 Map 来简化订单类型和描述的映射
        Map<String, String> orderTypeMap = new HashMap<>();
        orderTypeMap.put(ORDER_TYPE_TEA_REORDER_PREFIX, "茶室订单续单");
        orderTypeMap.put(ORDER_TYPE_MAHJONG_REORDER_PREFIX, "棋牌订单续单");
        orderTypeMap.put(ORDER_TYPE_BILLIARDS_REORDER_PREFIX, "台球订单续单");
        orderTypeMap.put(ORDER_TYPE_TEA_PREFIX, "茶室订单");
        orderTypeMap.put(ORDER_TYPE_MAHJONG_PREFIX, "棋牌订单");
        orderTypeMap.put(ORDER_TYPE_BILLIARDS_PREFIX, "台球订单");
        orderTypeMap.put(ORDER_TYPE_CONTAINER_PREFIX, "商品订单");

        // 遍历 Map 来获取描述
        for (Map.Entry<String, String> entry : orderTypeMap.entrySet()) {
            if (orderNo.startsWith(entry.getKey())) {
                desc = entry.getValue() + "：已支付" + payFee + "元";
                return desc; // 找到匹配后直接返回
            }
        }

        throw new ServiceException("非法的订单类型");
    }

    private void recordOrderHistory(String orderNo, String oldStatus, String newStatus, BigDecimal newFee, Long userId, String phone, String description) {
        if (!orderOperService.recordOrderHistory(orderNo, ServiceConstants.ORDER_OPERATION_PAY, oldStatus, newStatus, BigDecimal.ZERO, newFee, userId, phone, description)) {
            throw new ServiceException("【订单履历-" + description + "】更新订单信息失败，订单号: " + orderNo);
        }
    }


//    private void createOrderOper(OrderVO orderVO) {
//        if(orderVO.getOrderNo().startsWith(ServiceConstants.ORDER_TYPE_RESERVE_PREFIX)){// 预约订单
//            /* 预订单--记录订单履历 */
//            if(!orderOperService.recordOrderHistory(orderVO.getOrderNo(),ServiceConstants.ORDER_OPERATION_PAY,
//                    orderVO.getStatus(),orderVO.getStatus(),BigDecimal.ZERO,orderVO.getPayFee(),orderVO.getUserId(),orderVO.getPhone(),"预约订单支付：已支付 "+orderVO.getPayFee()+"元")){
//                throw new ServiceException("【订单履历-预约订单支付】更新订单信息失败");
//            }
//        } else if (orderVO.getOrderNo().startsWith(ServiceConstants.ORDER_TYPE_REORDER_PREFIX)){// 续费订单
//            if(!orderOperService.recordOrderHistory(orderVO.getOrderNo(),ServiceConstants.ORDER_OPERATION_PAY,
//                    orderVO.getStatus(),orderVO.getStatus(),BigDecimal.ZERO,orderVO.getPayFee(),orderVO.getUserId(),orderVO.getPhone(),"续订单支付：已支付 "+orderVO.getPayFee()+"元")){
//                throw new ServiceException("【订单履历-续订单支付】更新订单信息失败");
//            }
//        } else if (orderVO.getOrderNo().startsWith(ServiceConstants.ORDER_TYPE_RECHARGE_PREFIX)) { // 充值订单
//            if(!orderOperService.recordOrderHistory(orderVO.getOrderNo(),ServiceConstants.ORDER_OPERATION_PAY,
//                    orderVO.getStatus(),orderVO.getStatus(),BigDecimal.ZERO,orderVO.getPayFee(),orderVO.getUserId(),orderVO.getPhone(),"充值订单支付：已支付 "+orderVO.getPayFee()+"元")){
//                throw new ServiceException("【订单履历-充值订单支付】更新订单信息失败");
//            }
//        }else {
//            throw new ServiceException("非法的订单类型");
//        }
//    }

    private void updateDividendAndChangeBalance(OrderVO orderVO,String payNo,String businessType) {
        List<DividendDetailVO> dividendDetailVOS = dividendDetailService.selectRlDividendDetailListByOrderNo(orderVO.getOrderNo());
        ServiceUtil.assertion(dividendDetailVOS.isEmpty(), "分账记录不存在");
        for(DividendDetailVO dividendDetailVO : dividendDetailVOS){
            DividendDetail dividendDetail = getDividendDetail(orderVO, dividendDetailVO);

            UserVO user = userService.selectUserById(dividendDetailVO.getPartnerId());
            ServiceUtil.assertion(user == null, "分账用户不存在");

            /* 记录账变  */
            int i = changeBalanceService.generateChangeBalance(orderVO.getOrderNo(), payNo, ServiceConstants.FLOW_TYPE_INCOME,
                    businessType, dividendDetail.getDividendAmount(), user.getUserId(), user.getUserName(), user.getPhonenumber(),user.getUserType());
            ServiceUtil.assertion(i == 0, "更新记录账变失败");

            int i2 = dividendDetailService.updateRlDividendDetail(dividendDetail);
            ServiceUtil.assertion(i2 == 0, "更新分账状态失败");
        }
    }

    private static @NotNull DividendDetail getDividendDetail(OrderVO orderVO, DividendDetailVO dividendDetailVO) {
        DividendDetail dividendDetail = new DividendDetail();
        dividendDetail.setStatus(ServiceConstants.DIVIDEND_STATUS_PAID);
        BigDecimal bigDecimal = dividendDetailVO.getDividendProportion()
                .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP)
                .multiply(orderVO.getPayFee().subtract(orderVO.getPlatformServiceFee()))
                .setScale(2, RoundingMode.HALF_UP);
        dividendDetail.setDividendAmount(bigDecimal);
        dividendDetail.setSettlementAmount(bigDecimal);//支付成功后的结算金额就是分账金额，如果发生退款，结算金额 = 分账金额 - 退款金额
        dividendDetail.setId(dividendDetailVO.getId());
        return dividendDetail;
    }

    private void updatePayBill(PayBillVO payBillVO,LocalDateTime payTime) {
        PayBill updatedPayBill =  new PayBill();
        updatedPayBill.setStatus(PayBillStatus.PAY_SUCCESS.getStatus());
        updatedPayBill.setPayTime(payTime);
        updatedPayBill.setPayId(payBillVO.getPayId());
        int i = paymentService.updatePayBill(updatedPayBill);
        ServiceUtil.assertion(i == 0, "更新支付订单状态失败");
    }

    private void updateOrder(OrderVO orderVO,LocalDateTime payTime,PayBillVO payBill) {
        Order updateOrder = new Order();
        updateOrder.setOrderId(orderVO.getOrderId());
        updateOrder.setPaid(ServiceConstants.ORDER_PAY_STATUS_PAID);
        // todo 如果支付时间在预约开始时间之前，则状态是待使用，如果在预约开始时间之后，则状态是使用中，如果支付时间在预约结束时间之后。这种请在下单前就做做判断，避免出现这种情况
        LocalDateTime reserveStartTime = DateUtils.toLocalDateTime(orderVO.getReserveStartTime());
        String status;
        if(payTime.isBefore(reserveStartTime)){
            status = ServiceConstants.ORDER_STATUS_PAYMENT_SUCCESS;
        }else{
            status = ServiceConstants.ORDER_STATUS_IN_USE;
        }
        updateOrder.setStatus(status);
        updateOrder.setPayTime(payTime);
        updateOrder.setPayChannel(payBill.getChannelId());
        ChannelVO channelVO = rlChannelService.selectChannelByChannelId(payBill.getChannelId());
        updateOrder.setChannelName(channelVO.getName());
        updateOrder.setChannelCost(payBill.getChannelCost());
        updateOrder.setPayId(payBill.getPayId());
        int i = orderService.updateRlOrder(updateOrder);
        ServiceUtil.assertion(i == 0, "更新订单状态失败");
    }


    /** 结算原订单 */
    private void closeOriginalOrder(String originalOrderNo) {
            Order updateOriginalOrder = new Order();
            updateOriginalOrder.setOrderNo(originalOrderNo);
            updateOriginalOrder.setStatus(ServiceConstants.ORDER_STATUS_COMPLETED);
            int i = orderService.updateRlOrderByOrderNo(updateOriginalOrder);
            ServiceUtil.assertion(i==0,"更新原订单状态失败");
    }


    private BigDecimal getCost(ChannelVO channel,BigDecimal payFee) {
        // 获取到渠道成本
        BigDecimal costRate = channel.getCostRate();
        BigDecimal bigDecimal = costRate.divide(new BigDecimal(100), 6, BigDecimal.ROUND_HALF_UP);
        BigDecimal cost = bigDecimal.multiply(payFee).setScale(2, BigDecimal.ROUND_HALF_UP);
        logger.info("【保存资金流水记录--订单支付】 成本==============bigDecimal=====================："+bigDecimal);
        logger.info("【保存资金流水记录--订单支付】 成本==============cost=====================："+cost);
        return cost;
    }



    private void asynchronousSaveCallbackLog(CallbackLog etCallbackLog) {
        //开异步线程保存回调参数
        scheduledExecutorService.schedule(() -> {
            logger.info("【微信支付回调】异步保存回调参数");
            etCallbackLog.setCreateTime(DateUtils.getNowDate());
            int i = callbackLogMapper.insertEtCallbackLog(etCallbackLog);
            if(i>0){
                logger.info("【微信支付回调】异步保存回调参数成功");
            }
        }, 0, TimeUnit.SECONDS);
    }


    /**
     * 微信退款回调
     */
    @Override
    public void weChatRefund(HttpServletRequest request) {
        String body = HttpUtils.getBody(request);
        CallbackLog etCallbackLog = new CallbackLog();
        etCallbackLog.setBody2(body);
        etCallbackLog.setType("2");
        logger.info("【微信退款回调】接收对象 : {}", JSON.toJSONString(body));
        // 解析通知数据
        Notification notification = JSON.parseObject(body, Notification.class);
        logger.info("【微信退款回调】转换成notification: {}", JSON.toJSONString(notification));
        // 退款成功通知
        if (NotifyEventType.REFUND_SUCCESS.getValue().equals(notification.getEventType())) {
            // 验签、解密并转换成 RefundNotification
            RefundNotification refundNotification = checkAndParse(request, body, RefundNotification.class);
            logger.info("【微信退款回调】转换成RefundNotification: {}", JSON.toJSONString(refundNotification));
            etCallbackLog.setBody(JSON.toJSONString(refundNotification));
            if (Status.SUCCESS.equals(refundNotification.getRefundStatus())) {
                /**
                 * 退款回调
                 *    1.更新分成表的退款金额、结算金额,按比例退款
                 *    2.增加订单中的退款金额
                 *      2.1 修改订单中的状态为8已退款
                 *    3.更新支付单中的退款金额为已退款
                 *      3.1 记录（转移）已退款金额
                 *    4.更新退款表状态
                 * */

                String outRefundNo = refundNotification.getOutRefundNo();
                Refund refund = etRefundService.selectEtRefundByRefundNo(outRefundNo);
                ServiceUtil.assertion(refund == null, "退款记录不存在");

                PayBillVO payBillVO = paymentService.selectPayBillByPayId(refund.getPayId());
                ServiceUtil.assertion(payBillVO == null, "支付订单不存在");

                Boolean execute = transactionTemplate.execute(e -> {
                    // 1.更新分成表的退款金额、结算金额、按比例退款
                    List<DividendDetailVO> dividendDetailVOS = dividendDetailService.selectRlDividendDetailListByOrderNo(payBillVO.getOrderNo());
                    OrderVO orderVO = orderService.selectRlOrderByOrderNo(payBillVO.getOrderNo());
                    int updateRefund = this.partnerRefund(dividendDetailVOS, refund.getAmount(), orderVO.getPayFee());
                    ServiceUtil.assertion(updateRefund == 0, "更新分成表退款金额失败");

                    // 2.增加订单中的退款金额
                    int addRefundAmount = orderService.addRefundAmountByOrderNo(payBillVO.getOrderNo(),refund.getAmount());
                    ServiceUtil.assertion(addRefundAmount == 0, "增加订单中的退款金额失败");

                    // 2.1修改订单中的状态为8已退款
                    Order order = new Order();
                    order.setOrderNo(payBillVO.getOrderNo());
                    order.setStatus(ServiceConstants.ORDER_STATUS_REFUNDED);
                    int updateOrder = orderService.updateRlOrderByOrderNo(order);
                    ServiceUtil.assertion(updateOrder == 0, "更新订单状态失败");

                    // 3.更新支付单中的退款金额为已退款
                    PayBill closeData = new PayBillVO();
                    closeData.setStatus(PayBillStatus.REFUNDED.getStatus());
                    PayBillQuery updateQuery = new PayBillQuery();
                    updateQuery.setStatusList(PayBillStatus.payedList());
                    updateQuery.setPayId(refund.getPayId());
                    int update = paymentService.updateByQuery(closeData,updateQuery);
                    ServiceUtil.assertion(update != 1, "修改订单状态失败");

                    //  3.1记录（转移）已退款金额
                    int recordAmount = paymentService.recordRefundAmount(refund.getPayId(), refund.getAmount());
                    ServiceUtil.assertion(recordAmount != 1, "修改退款金额失败");

                    // 4.更新退款表状态为成功
                    Refund rlRefund = new Refund();
                    rlRefund.setRefundNo(outRefundNo);
                    rlRefund.setStatus(REFUND_STATUS_SUCCESS);
                    int i3 = etRefundService.updateEtRefundByRefundNo(rlRefund);
                    ServiceUtil.assertion(i3 == 0, "【微信退款回调】更新退款单失败");
                    return Boolean.TRUE;
                });
                if(Boolean.FALSE.equals(execute))throw new ServiceException("微信支付回调失败");
                logger.info("【微信退款回调】全部结束！！！！！");
            }
        }
        //异步保存回调日志
        asynchronousSaveCallbackLog(etCallbackLog);
    }


    /**
     * 更新分成的退款金额
     *
     * @param dividendDetailList  分成列表
     * @param refundAmount 本次退款金额
     * @param totalAmount   订单总金额
     */
    private int partnerRefund(List<DividendDetailVO> dividendDetailList, BigDecimal refundAmount, BigDecimal totalAmount) {
        if (CollectionUtils.isEmptyElement(dividendDetailList)) {
            return 0;
        }

        BigDecimal totalDividendProportion = BigDecimal.ZERO;
        BigDecimal totalRefundCalculated = BigDecimal.ZERO;
        DividendDetailVO merchantDividendDetail = null;

        // 计算总分红比例和每个分成记录的退款金额
        for (DividendDetailVO detail : dividendDetailList) {
            totalDividendProportion = totalDividendProportion.add(detail.getDividendProportion());

            if ("01".equals(detail.getPartnerType())) {
                merchantDividendDetail = detail; // 找到商户的分成记录
            }

            BigDecimal refundForDetail = detail.getDividendProportion()
                    .divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP)
                    .multiply(refundAmount)
                    .setScale(2, RoundingMode.HALF_UP);
            totalRefundCalculated = totalRefundCalculated.add(refundForDetail);
            detail.setRefundAmount(refundForDetail);
            int i = dividendDetailService.updateRefundAmount(detail.getId(), detail.getDividendAmount(),refundForDetail);
            ServiceUtil.assertion(i == 0, "更新分成表退款金额失败");
        }

        // 检查总分红比例是否为100%
        ServiceUtil.assertion(!(totalDividendProportion.compareTo(new BigDecimal("100")) == 0), "总分红比例必须为100%");

        // 如果总退款金额有误差，由商户承担差额
        BigDecimal difference = totalRefundCalculated.subtract(refundAmount).abs();
        if (difference.compareTo(BigDecimal.ZERO) > 0) {
            ServiceUtil.assertion(merchantDividendDetail == null, "没有找到商户的分成记录");
            BigDecimal adjustedMerchantRefund = merchantDividendDetail.getRefundAmount().subtract(difference).setScale(2, RoundingMode.HALF_UP);
            merchantDividendDetail.setRefundAmount(adjustedMerchantRefund);
        }

        // 处理误差
//        BonusUtil.handleRefundAmountDiff(refundList, bonusList, dividedAmount, refundAmount);

        // 校验金额
        for (DividendDetailVO bonus : dividendDetailList) {
            ServiceUtil.assertion(bonus.getRefundAmount().compareTo(BigDecimal.ZERO) < 0, "退款金额不允许小于0");
        }
        BigDecimal sum = CollectionUtils.sumDecimal(dividendDetailList, DividendDetailVO::getRefundAmount);
        ServiceUtil.assertion(sum.compareTo(refundAmount) != 0, "退款金额分配出错");

        for (DividendDetailVO dividendDetail : dividendDetailList) {
            dividendDetail.setRefundAmount(dividendDetail.getRefundAmount().setScale(2, RoundingMode.HALF_UP));
        }

        // 执行退款逻辑
        return executeRefund(dividendDetailList);
    }

    // 执行分成退款
    private int executeRefund(List<DividendDetailVO> refundList) {
        Integer result = transactionTemplate.execute(status -> {
            int update = 0;

            // 余额退款
            for (DividendDetailVO dividendDetail : refundList) {
                UserVO userVO = userService.selectUserById(dividendDetail.getPartnerId());
                ServiceUtil.assertion(userVO.getBalance().compareTo(dividendDetail.getRefundAmount()) < 0, "可退款金额不足");

                /* 记录账变  */
                int i = changeBalanceService.generateChangeBalance(dividendDetail.getOrderNo(), null, ServiceConstants.FLOW_TYPE_DISBURSE,
                        ServiceConstants.REFUND, dividendDetail.getRefundAmount(), dividendDetail.getPartnerId(), dividendDetail.getPartnerName(), dividendDetail.getPartnerPhone(),dividendDetail.getPartnerType());
                ServiceUtil.assertion(i == 0, "更新记录账变失败");
                update++;
            }

            // 创建分成退款记录
            List<DividendRefund> bonusRefundList = dividendRefundConverter.toPo(refundList);
            int insertBonusRefund = dividendRefundService.batchInsert(bonusRefundList);
            ServiceUtil.assertion(insertBonusRefund != bonusRefundList.size(), "创建分成退款记录失败");

            return update;
        });

        return result == null ? 0 : result;
    }

    /**
     * 验签并解析
     * @param request 请求
     * @param body 请求体
     * @param clazz 返回值类型
     */
    private <T> T checkAndParse(HttpServletRequest request, String body, Class<T> clazz) {
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(request.getHeader("Wechatpay-Serial"))
                .nonce(request.getHeader("Wechatpay-Nonce"))
                .signature(request.getHeader("Wechatpay-Signature"))
                .timestamp(request.getHeader("Wechatpay-Timestamp"))
                .body(body)
                .build();
        // 验签
        String wechatpaySerial = request.getHeader("Wechatpay-Serial");
        NotificationParser notificationParser = getNotificationParser(wechatpaySerial);
        return notificationParser.parse(requestParam, clazz);
    }


    public NotificationParser getNotificationParser(String wechatpaySerial) {
        // 根据证书序列号获取运营商
        ChannelVO channelVO = rlChannelService.selectChannelBySerialNumber(wechatpaySerial);
        String privateKeyPath = channelVO.getPrivateKeyPath();
        logger.info("回调是否是测试环境------{}", isTest);
        if(isTest){
            privateKeyPath = path;
        }
        if(ObjectUtil.isNull(channelVO)){
            throw new ServiceException("【微信支付回调】根据证书序列号获取支付渠道失败");
        }else{
            NotificationConfig config = new RSAAutoCertificateConfig.Builder()
                    .merchantId(channelVO.getMerchantId())
                    .privateKeyFromPath(privateKeyPath)
                    .merchantSerialNumber(channelVO.getMerchantSerialNumber())
                    .apiV3Key(channelVO.getApiV3Key())
                    .build();
            return new NotificationParser(config);
        }
    }
}
