package com.czg.service.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.account.dto.shopuser.ShopUserMoneyEditDTO;
import com.czg.account.entity.*;
import com.czg.account.service.*;
import com.czg.config.RabbitPublisher;
import com.czg.config.RedisCst;
import com.czg.constant.TableValueConstant;
import com.czg.entity.req.*;
import com.czg.entity.resp.*;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.exception.CzgException;
import com.czg.exception.PaySuccessException;
import com.czg.market.dto.MemberOrderDTO;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.entity.MkShopRecharge;
import com.czg.market.entity.MkShopRechargeDetail;
import com.czg.market.service.*;
import com.czg.market.vo.MkShopRechargeVO;
import com.czg.order.dto.BigDecimalDTO;
import com.czg.order.dto.CheckOrderPay;
import com.czg.order.dto.OrderInfoRefundDTO;
import com.czg.market.entity.MemberOrder;
import com.czg.order.entity.OrderDetail;
import com.czg.order.entity.OrderInfo;
import com.czg.order.entity.OrderPayment;
import com.czg.order.enums.PayEnums;
import com.czg.order.service.*;
import com.czg.resp.CzgRespCode;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.CzgPayService;
import com.czg.service.RedisService;
import com.czg.service.market.service.impl.MemberOrderServiceImpl;
import com.czg.service.order.dto.*;
import com.czg.service.order.enums.OrderStatusEnums;
import com.czg.service.order.mapper.OrderPaymentMapper;
import com.czg.service.order.service.PayService;
import com.czg.system.enums.SysParamCodeEnum;
import com.czg.system.service.SysParamsService;
import com.czg.utils.AssertUtil;
import com.czg.utils.MD5Util;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author ww
 * @description
 */
@Slf4j
@Service
public class PayServiceImpl implements PayService {

    @DubboReference
    private ShopMerchantService shopMerchantService;
    @DubboReference
    private SysParamsService sysParamsService;
    @DubboReference
    private ShopUserService shopUserService;
    @DubboReference
    private UserInfoService userInfoService;
    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private ShopUserFlowService userFlowService;
    @Resource
    private MkShopCouponRecordService recordService;
    @DubboReference
    private MemberPointsService pointsService;
    @DubboReference
    private FreeDineConfigService freeConfigService;
    @Resource
    private CzgPayService czgPayService;
    @Resource
    private OrderInfoService orderInfoService;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private OrderPaymentService paymentService;
    @Resource
    private OrderPaymentMapper paymentMapper;
    @Resource
    private CreditBuyerOrderService buyerOrderService;
    @Resource
    private RedisService redisService;
    @Resource
    private RabbitPublisher rabbitPublisher;
    @DubboReference
    private MemberOrderService memberOrderService;
    @Resource
    private MkShopRechargeService shopRechargeService;
    @Resource
    private MkShopRechargeDetailService shopRechargeDetailService;
    @Resource
    private TbMemberConfigService memberConfigService;
    @Resource
    private MkDistributionUserService distributionUserService;

    private final BigDecimal MONEY_RATE = new BigDecimal("100");

    private OrderInfo checkPay(CheckOrderPay checkOrderPay) {
        OrderInfo orderInfo = orderInfoService.checkOrderPay(checkOrderPay);
        if (orderInfo.getOrderAmount().compareTo(BigDecimal.ZERO) == 0) {
            //发送打票信息
            //orderId_0_0  订单ID_先付后付(1先付0后付)_订单状态 0未完成 1完成
            //orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_0"
            rabbitPublisher.sendOrderPrintMsg(orderInfo.getId() + "_" + (!"after-pay".equals(orderInfo.getPayMode()) ? 1 : 0) + "_1", orderInfo.getIsPrint() == 1);
            redisService.del(RedisCst.classKeyExpired.EXPIRED_ORDER + orderInfo.getId());
            throw new PaySuccessException("支付成功");
        }
        return orderInfo;
    }

    /**
     * 会员充值 校验
     *
     * @return 是否是霸王餐充值
     */
    private boolean checkPayVip(VipPayParamDTO payParam) {

        if (payParam.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new ValidateException("充值金额不正确");
        }
        if (payParam.getOrderId() != null) {
            FreeDineConfig freeConfig = freeConfigService.getById(shopInfoService.getMainIdByShopId(payParam.getShopId()));
            AssertUtil.isNull(freeConfig, "该店铺未启用霸王餐");
            if (!freeConfig.getEnable()) {
                throw new CzgException("该店铺未启用霸王餐");
            }
            CheckOrderPay checkOrderPay = payParam.getCheckOrderPay();
//            CheckOrderPay checkOrderPay = BeanUtil.copyProperties(payParam, CheckOrderPay.class);
            OrderInfo orderInfo = orderInfoService.checkOrderPay(checkOrderPay.setFreeDine(true).setWithCoupon(freeConfig.getWithCoupon()).setWithPoints(freeConfig.getWithPoints()));
            payParam.setAmount(orderInfo.getOrderAmount().multiply(BigDecimal.valueOf(freeConfig.getRechargeTimes())));
            return true;
        }
        return false;
    }


    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Object> creditPayOrder(OrderPayParamDTO payParam) {
        AssertUtil.isNull(payParam.getCreditBuyerId(), "请选择挂账人后支付");
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        orderInfo.setCreditBuyerId(payParam.getCreditBuyerId());
        orderInfoService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
                LocalDateTime.now(), null, PayEnums.CREDIT_PAY);
        //挂账后续逻辑
        buyerOrderService.save(payParam.getCreditBuyerId().toString(), orderInfo.getId());
        return CzgResult.success();
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Object> cashPayOrder(OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        orderInfoService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
                LocalDateTime.now(), null, PayEnums.CASH_PAY);
        return CzgResult.success();
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Object> vipPayOrder(OrderPayParamDTO payParam) {
        ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
        if (!shopInfo.getIsAccountPay().equals(1)) {
            return CzgResult.failure("支付失败，店铺暂未开启会员余额支付。");
        }
        ShopUser shopUser = new ShopUser();
        if ("scanCode".equals(payParam.getPayType())) {
            AssertUtil.isBlank(payParam.getAuthCode(), "会员码不能为空");
            Object o = redisService.get(RedisCst.SHOP_USER_DYNAMIC_CODE + payParam.getShopId() + ":" + payParam.getAuthCode());
            AssertUtil.isNull(o, "会员码已失效");
            shopUser = shopUserService.getById(o.toString());
        } else {
            if ("userPay".equals(payParam.getPayType())) {
                AssertUtil.isNull(payParam.getShopUserId(), "请选择付款人后重试");
                shopUser = shopUserService.getById(payParam.getShopUserId());
            } else if ("accountPay".equals(payParam.getPayType())) {
                shopUser = shopUserService.getById(payParam.getShopUserId());
                AssertUtil.isNull(shopUser, "会员不存在");
                UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
                AssertUtil.isNull(userInfo, "用户信息不存在");
                if (userInfo.getUsePayPwd() == 1) {
                    AssertUtil.isBlank(payParam.getPwd(), "支付密码不能为空");
                    if (userInfo.getPayPwd() == null || !userInfo.getPayPwd().equals(MD5Util.md5AsHex(payParam.getPwd()))) {
                        return CzgResult.failure("支付密码错误");
                    }
                }
            }
        }
        if (shopUser == null || shopUser.getId() == null) {
            AssertUtil.isNull(shopUser, "会员不存在");
        }
        payParam.getCheckOrderPay().setUserId(shopUser.getUserId());
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        if (shopInfo.getIsHeadShop().equals(1)) {
            if (!shopUser.getMainShopId().equals(orderInfo.getShopId())) {
                return CzgResult.failure("违规操作，请确认店铺后重试");
            }
        } else {
            boolean exists = shopInfoService.exists(QueryWrapper.create()
                    .eq(ShopInfo::getMainId, shopInfo.getMainId())
                    .eq(ShopInfo::getId, orderInfo.getShopId()));
            if(!exists){
                return CzgResult.failure("违规操作，请确认店铺后重试");
            }
        }
        if (shopUser.getAmount().compareTo(orderInfo.getOrderAmount()) < 0) {
            return CzgResult.failure("会员余额不足");
        }
        ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                .setId(shopUser.getId())
                .setMoney(orderInfo.getOrderAmount())
                .setType(0)
                .setBizEnum(ShopUserFlowBizEnum.ORDER_PAY)
                .setRelationId(orderInfo.getId());
        //更新会员余额 并生成流水
        if (payParam.getCheckOrderPay() != null && StrUtil.isNotBlank(payParam.getCheckOrderPay().getRemark())) {
            orderInfo.setRemark(payParam.getCheckOrderPay().getRemark());
        }

        log.info("发放经验值");
        memberConfigService.deliver(shopUser, TableValueConstant.MemberExpFlow.Type.COST, orderInfo.getOrderAmount(), null, orderInfo.getId());

        Long flowId = shopUserService.updateMoney(shopUserMoneyEditDTO);
        orderInfoService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
                LocalDateTime.now(), flowId, PayEnums.VIP_PAY);



        return CzgResult.success();
    }

    @Override
    public CzgResult<Map<String, Object>> rechargePayOrder(String clintIp, OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
//        if (!shopInfo.getIsAccountPay().equals(1)) {
//            return CzgResult.failure("支付失败，店铺暂未开启会员余额支付。");
//        }
        AssertUtil.isNull(payParam.getShopUserId(), "请选择付款人后重试");
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "支付失败 该店铺用户不存在");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
        AssertUtil.isNull(payParam.getRechargeId(), "请选择充值配置后重试");
        AssertUtil.isNull(payParam.getRechargeDetailId(), "请选择充值配置后重试");
        //查询活动Id 获取金额字段
        MkShopRechargeDetail rechargeDetail = shopRechargeDetailService.getOne(
                new QueryWrapper().eq(MkShopRechargeDetail::getId, payParam.getRechargeDetailId())
                        .eq(MkShopRechargeDetail::getShopRechargeId, payParam.getRechargeId()));
        AssertUtil.isNull(rechargeDetail, "充值配置不存在");
        if (orderInfo.getOrderAmount().compareTo(rechargeDetail.getAmount()) >= 0) {
            log.info("充值金额小于订单金额,充值金额:{} 订单金额:{}", rechargeDetail.getAmount(), orderInfo.getOrderAmount());
            return CzgResult.failure("支付失败 充值金额必须大雨订单金额");
        }
        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), shopUser.getId(), "memberIn", payOrderNo,
                "", rechargeDetail.getAmount(), rechargeDetail.getId()));
        upOrderPayInfo(orderInfo.getId(), PayEnums.VIP_PAY, paymentId,
                payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        return ltPay(payParam.getShopId(), payParam.getPayType(), new CzgLtPayReq(payOrderNo, rechargeDetail.getAmount().multiply(MONEY_RATE).longValue(),
                payParam.getPayType(), "充值并支付", "wechatPay".equals(payParam.getPayType()) ? userInfo.getWechatOpenId() : userInfo.getAlipayOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Map<String, Object>> h5PayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), orderInfo.getId(),
                "order", payOrderNo, "", orderInfo.getOrderAmount()));
        upOrderPayInfo(orderInfo.getId(), PayEnums.H5_PAY, paymentId,
                payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        return h5Pay(payParam.getShopId(), new CzgH5PayReq(payOrderNo, orderInfo.getOrderAmount().multiply(MONEY_RATE).longValue(),
                "点餐支付", clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }


    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Map<String, Object>> jsPayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), orderInfo.getId(),
                "order", payOrderNo, "", orderInfo.getOrderAmount()));
        upOrderPayInfo(orderInfo.getId(), "aliPay".equals(payParam.getPayType()) ? PayEnums.ALIPAY_MINI : PayEnums.WECHAT_MINI, paymentId,
                payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        return jsPay(payParam.getShopId(), payParam.getPayType(), new CzgJsPayReq(payOrderNo, orderInfo.getOrderAmount().multiply(MONEY_RATE).longValue(),
                "点餐支付", payParam.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Map<String, Object>> js2PayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        OrderInfo orderInfo;
        if (payParam.getCheckOrderPay().getOrderId() == null) {
            if (payParam.getCheckOrderPay().getOrderAmount() == null || payParam.getCheckOrderPay().getOrderAmount().compareTo(BigDecimal.ZERO) <= 0) {
                throw new CzgException("支付金额不合法");
            }
            orderInfo = orderInfoService.createPayOrder(payParam.getShopId(), payParam.getCheckOrderPay().getOrderAmount(),
                    payParam.getCheckOrderPay().getRemark());
        } else {
            orderInfo = orderInfoService.getById(payParam.getCheckOrderPay().getOrderId());
        }
        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), orderInfo.getId(),
                "order", payOrderNo, "", orderInfo.getOrderAmount()));
        upOrderPayInfo(orderInfo.getId(), "aliPay".equals(payParam.getPayType()) ? PayEnums.ALIPAY_MINI : PayEnums.WECHAT_MINI, paymentId,
                payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        return jsPay(payParam.getShopId(), payParam.getPayType(), new CzgJsPayReq(payOrderNo, orderInfo.getOrderAmount().multiply(MONEY_RATE).longValue(),
                "点餐支付", payParam.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Map<String, Object>> ltPayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), orderInfo.getId(),
                "order", payOrderNo, "", orderInfo.getOrderAmount()));
        upOrderPayInfo(orderInfo.getId(), "aliPay".equals(payParam.getPayType()) ? PayEnums.ALIPAY_MINI : PayEnums.WECHAT_MINI, paymentId,
                payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        return ltPay(payParam.getShopId(), payParam.getPayType(), new CzgLtPayReq(payOrderNo, orderInfo.getOrderAmount().multiply(MONEY_RATE).longValue(),
                payParam.getPayType(), "点餐支付", payParam.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Map<String, Object>> scanPayOrder(@NonNull String clintIp, OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());


        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
        if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
            throw new CzgException("未开启自定义充值金额");
        }
        Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
        BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
        payParam.setAmount(amount);
        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), orderInfo.getId(),
                "order", payOrderNo, "", orderInfo.getOrderAmount()));
        upOrderPayInfo(orderInfo.getId(), PayEnums.MAIN_SCAN, paymentId,
                payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        return scanPay(payParam.getShopId(), new CzgScanPayReq(payOrderNo, orderInfo.getOrderAmount().multiply(MONEY_RATE).longValue(),
                "点餐支付", clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional(noRollbackFor = PaySuccessException.class)
    public CzgResult<Map<String, Object>> microPayOrder(OrderPayParamDTO payParam) {
        OrderInfo orderInfo = checkPay(payParam.getCheckOrderPay());
        AssertUtil.isBlank(payParam.getAuthCode(), "扫描码不能为空");


        if (payParam.getShopUserId() != null) {
            ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
            MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
            if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
                throw new CzgException("未开启自定义充值金额");
            }
            Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
            BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
            payParam.setAmount(amount);
        }

        String payOrderNo = orderInfo.getPlatformType() + IdUtil.getSnowflakeNextId();
        Long paymentId = initOrderPayment(new OrderPayment(payParam.getShopId(), orderInfo.getId(),
                "order", payOrderNo, payParam.getAuthCode(), orderInfo.getOrderAmount()));
        CzgResult<Map<String, Object>> mapCzgResult = microPay(payParam.getShopId(), new CzgMicroPayReq(payOrderNo, orderInfo.getOrderAmount().multiply(MONEY_RATE).longValue(),
                "点餐支付", payParam.getAuthCode(), payParam.getBuyerRemark(), ""));
        if (mapCzgResult.getCode() == 200) {
            orderInfoService.upOrderInfo(orderInfo, orderInfo.getOrderAmount(),
                    LocalDateTime.now(), paymentId, PayEnums.BACK_SCAN);
        } else {
            upOrderPayInfo(orderInfo.getId(), PayEnums.BACK_SCAN, paymentId,
                    payParam.getCheckOrderPay() == null ? null : payParam.getCheckOrderPay().getRemark());
        }
        return mapCzgResult;
    }

    @Override
    @Transactional
    public CzgResult<Object> cashPayVip(VipPayParamDTO payParam) {
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
        AssertUtil.isNull(shopInfo, "店铺不存在");
        if (shopInfo.getIsMemberInPwd().equals(1)) {
            AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
            AssertUtil.isBlank(payParam.getPwd(), "请输入操作密码后充值");
            if (!shopInfo.getOperationPwd().equals(SecureUtil.md5(payParam.getPwd()))) {
                return CzgResult.failure("支付密码错误");
            }
        }
        if (shopUser.getIsVip().equals(0)) {
            //更新会员
            ShopUser updateInfo = new ShopUser();
            updateInfo.setIsVip(1);
            updateInfo.setJoinTime(LocalDateTime.now());
            updateInfo.setId(payParam.getShopUserId());
            shopUserService.updateById(updateInfo);
        }
        ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                .setId(shopUser.getId())
                .setMoney(payParam.getAmount())
                .setType(1)
                .setRemark("现金充值")
                .setBizEnum(ShopUserFlowBizEnum.CASH_IN);
        //更新会员余额 并生成流水
        Long flowId = shopUserService.updateMoney(shopUserMoneyEditDTO);
        //TODO 以前的会员活动
        //shopActivateService.giveActivate(shopUser, payParam.getAmount(), payParam.getActivateId(), flowId);
        return CzgResult.success();
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> jsPayVip(String clintIp, VipPayParamDTO payParam) {
        boolean isFree = checkPayVip(payParam);
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        String payOrderNo = payParam.getPlatformType() + IdUtil.getSnowflakeNextId();
        initOrderPayment(new OrderPayment(payParam.getShopId(), shopUser.getId(), isFree ? "free" : "memberIn", payOrderNo,
                "", payParam.getAmount(), isFree ? payParam.getOrderId() : payParam.getActivateId()));
        return jsPay(payParam.getShopId(), payParam.getPayType(), new CzgJsPayReq(payOrderNo, payParam.getAmount().multiply(MONEY_RATE).longValue(),
                "会员充值", payParam.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CzgResult<Map<String, Object>> ltPayMember(String clientIP, VipMemberPayParamDTO payParam) {
        ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, shopInfoService.getMainIdByShopId(payParam.getShopId())).eq(ShopUser::getId, payParam.getShopUserId()));
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        UserInfo userInfo = userInfoService.getById(shopUser.getUserId());
        MemberOrder memberOrder = memberOrderService.createMemberOrder(new MemberOrderDTO().setName(payParam.getName())
                .setNum(1).setNickName(payParam.getNickName())
                .setOrderType(payParam.getOrderType())
                .setPlatformType(payParam.getPlatformType()).setSex(payParam.getSex()).setUserId(shopUser.getUserId()).setShopId(payParam.getShopId()).setBirthDay(payParam.getBirthDay()));

        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");
        String payOrderNo = payParam.getPlatformType() + IdUtil.getSnowflakeNextId();
        initOrderPayment(new OrderPayment(payParam.getShopId(), shopUser.getId(), "memberPay", payOrderNo,
                "", memberOrder.getAmount(), memberOrder.getId()));
        return ltPay(payParam.getShopId(), payParam.getPayType(), new CzgLtPayReq(payOrderNo, memberOrder.getAmount().multiply(MONEY_RATE).longValue(),
                payParam.getPayType(), "会员充值", "wechatPay".equals(payParam.getPayType()) ? userInfo.getWechatOpenId() : userInfo.getAlipayOpenId(), clientIP, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> ltPayVip(String clintIp, VipPayParamDTO payParam) {
        // 霸王餐校验
        boolean isFree = checkPayVip(payParam);
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        AssertUtil.isBlank(payParam.getOpenId(), "用户小程序ID不能为空");
        AssertUtil.isBlank(payParam.getPayType(), "支付方式不能为空");

        MkShopRechargeVO rechargeVO = shopRechargeService.detail(payParam.getShopId());
        if (payParam.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
            throw new CzgException("未开启自定义充值金额");
        }
        Long mainShopId = shopInfoService.getMainIdByShopId(payParam.getShopId());
        if (isFree) {
            BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, payParam.getShopId(), shopUser.getUserId(), payParam.getRechargeDetailId(), payParam.getAmount());
            payParam.setAmount(amount);
        }

        String payOrderNo = payParam.getPlatformType() + IdUtil.getSnowflakeNextId();
        initOrderPayment(new OrderPayment(payParam.getShopId(), shopUser.getId(), isFree ? "free" : "memberIn", payOrderNo,
                "", payParam.getAmount(), isFree ? payParam.getOrderId() : payParam.getActivateId()));
        return ltPay(payParam.getShopId(), payParam.getPayType(), new CzgLtPayReq(payOrderNo, payParam.getAmount().multiply(MONEY_RATE).longValue(),
                payParam.getPayType(), "会员充值", payParam.getOpenId(), clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    public CzgResult<Map<String, Object>> recharge(String clientIP, VipPayParamDTO rechargeDTO, Long shopUserId) {
        boolean isFree = checkPayVip(rechargeDTO);
        Long mainShopId = shopInfoService.getMainIdByShopId(rechargeDTO.getShopId());

        ShopUser shopUser = shopUserService.getOne(new QueryWrapper().eq(ShopUser::getMainShopId, mainShopId)
                .eq(ShopUser::getId, shopUserId));
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        MkShopRechargeVO rechargeVO = shopRechargeService.detail(rechargeDTO.getShopId());
        if (rechargeDTO.getRechargeDetailId() == null && rechargeVO.getIsCustom() == 0) {
            throw new CzgException("未开启自定义充值金额");
        }
        UserInfo userInfo = userInfoService.getById(shopUser.getUserId());

        BigDecimal amount = shopRechargeService.checkRecharge(mainShopId, rechargeDTO.getShopId(), shopUser.getUserId(), rechargeDTO.getRechargeDetailId(), rechargeDTO.getAmount());
        String payOrderNo = rechargeDTO.getPlatformType() + IdUtil.getSnowflakeNextId();
        initOrderPayment(new OrderPayment(rechargeDTO.getShopId(), shopUser.getId(), isFree ? "free" : "memberIn", payOrderNo,
                "", amount, isFree ? rechargeDTO.getOrderId() : rechargeDTO.getRechargeDetailId()));
        return ltPay(rechargeDTO.getShopId(), rechargeDTO.getPayType(), new CzgLtPayReq(payOrderNo, amount.multiply(MONEY_RATE).longValue(),
                rechargeDTO.getPayType(), "会员充值", "wechatPay".equals(rechargeDTO.getPayType()) ? userInfo.getWechatOpenId() : userInfo.getAlipayOpenId(), clientIP, rechargeDTO.getReturnUrl(), rechargeDTO.getBuyerRemark(), ""));
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> scanPayVip(String clintIp, VipPayParamDTO payParam) {
        boolean isFree = checkPayVip(payParam);
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        String payOrderNo = payParam.getPlatformType() + IdUtil.getSnowflakeNextId();
        initOrderPayment(new OrderPayment(payParam.getShopId(), shopUser.getId(), isFree ? "free" : "memberIn", payOrderNo,
                "", payParam.getAmount(), isFree ? payParam.getOrderId() : payParam.getActivateId()));
        return scanPay(payParam.getShopId(), new CzgScanPayReq(payOrderNo, payParam.getAmount().multiply(MONEY_RATE).longValue(),
                "会员充值", clintIp, payParam.getReturnUrl(), payParam.getBuyerRemark(), ""));
    }

    @Override
    @Transactional
    public CzgResult<Map<String, Object>> microPayVip(VipPayParamDTO payParam) {
        boolean isFree = checkPayVip(payParam);
        AssertUtil.isBlank(payParam.getAuthCode(), "扫描码不能为空");
        ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
        AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
        String payOrderNo = payParam.getPlatformType() + IdUtil.getSnowflakeNextId();
        initOrderPayment(new OrderPayment(payParam.getShopId(), shopUser.getId(), isFree ? "free" : "memberIn", payOrderNo,
                payParam.getAuthCode(), payParam.getAmount(), isFree ? payParam.getOrderId() : payParam.getActivateId()));
        CzgResult<Map<String, Object>> mapCzgResult = microPay(payParam.getShopId(), new CzgMicroPayReq(payOrderNo, payParam.getAmount().multiply(MONEY_RATE).longValue(),
                "会员充值", payParam.getAuthCode(), payParam.getBuyerRemark(), ""));
        mapCzgResult.setData(Map.of("payOrderNo", payOrderNo));
        return mapCzgResult;
    }

    @Override
    public CzgResult<Map<String, BigDecimal>> refundVipBefore(VipRefundDTO payParam) {
        Map<String, BigDecimal> resultMap = new HashMap<>(5);
        ShopUser shopUser = shopUserService.getShopUserInfo(payParam.getShopId(), payParam.getUserId());
        AssertUtil.isNull(shopUser, "该店铺用户不存在");
        ShopUserFlow inFlow = userFlowService.getById(payParam.getFlowId());
        AssertUtil.isNull(inFlow, "充值记录不存在");
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(ShopUserFlow::getRelationId, payParam.getFlowId());
        queryWrapper.eq(ShopUserFlow::getBizCode, ShopUserFlowBizEnum.AWARD_IN.getCode());
        ShopUserFlow giftFlow = userFlowService.getOne(queryWrapper);
        resultMap.put("amount", shopUser.getAmount());
        resultMap.put("inAmount", inFlow.getAmount());
        resultMap.put("inRefundAmount", inFlow.getRefundAmount());
        resultMap.put("giftAmount", giftFlow == null ? BigDecimal.ZERO : giftFlow.getAmount());
        resultMap.put("giftRefundAmount", giftFlow == null ? BigDecimal.ZERO : giftFlow.getRefundAmount());
        return CzgResult.success(resultMap);
    }

    @Override
    @Transactional
    public CzgResult<Object> refundVip(VipRefundDTO refPayParam) {
        ShopInfo shopInfo = shopInfoService.getById(refPayParam.getShopId());
        if (shopInfo.getIsReturnPwd().equals(1)) {
            AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
            if (!SecureUtil.md5(refPayParam.getPwd()).equals(shopInfo.getOperationPwd())) {
                throw new CzgException("操作密码错误");
            }
        }
        ShopUser shopUser = shopUserService.getShopUserInfo(refPayParam.getShopId(), refPayParam.getUserId());
        ShopUserFlow inFlow = userFlowService.getById(refPayParam.getFlowId());
        AssertUtil.isNull(inFlow, "充值记录不存在");
        if ("cashIn".equals(inFlow.getBizCode()) || "adminIn".equals(inFlow.getBizCode())) {
            refPayParam.setCashRefund(true);
        }
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(ShopUserFlow::getRelationId, refPayParam.getFlowId());
        queryWrapper.eq(ShopUserFlow::getBizCode, ShopUserFlowBizEnum.AWARD_IN.getCode());
        ShopUserFlow giftFlow = userFlowService.getOne(queryWrapper);
        if ((inFlow.getAmount().subtract(inFlow.getRefundAmount())).compareTo(refPayParam.getRefAmount()) < 0) {
            return CzgResult.failure("退款失败，退款金额不可大于可退金额");
        }
        //用户余额减去赠送金额 小于 退款金额 则需要勾选 超额退款
        if (giftFlow != null) {
            if (shopUser.getAmount().subtract(giftFlow.getAmount().subtract(giftFlow.getRefundAmount())).compareTo(refPayParam.getRefAmount()) < 0 && !refPayParam.isOutOfRange()) {
                return CzgResult.failure("超额退款,请勾选 超额退款后重试");
            }
        } else {
            if (shopUser.getAmount().compareTo(refPayParam.getRefAmount()) < 0 && !refPayParam.isOutOfRange()) {
                return CzgResult.failure("超额退款,请勾选 超额退款后重试");
            }
        }
        Long refPaymentId = null;
        if (!refPayParam.isCashRefund()) {
            OrderPayment payment;
            if (inFlow.getRelationId() != null) {
                payment = paymentService.getById(inFlow.getRelationId());
            } else {
                return CzgResult.failure("退款失败,该充值记录不存在");
            }
            String refPayOrderNo = "REFVIP" + IdUtil.getSnowflakeNextId();
            refPaymentId = initOrderPayment(new OrderPayment(refPayParam.getShopId(), shopUser.getId(),
                    "memberRefund", refPayOrderNo, null, refPayParam.getRefAmount()));
            CzgResult<CzgRefundResp> refund = refund(refPayParam.getShopId(), new CzgRefundReq(refPayOrderNo, refPayParam.getRemark(),
                    refPayParam.getRefAmount().multiply(MONEY_RATE).longValue(), payment.getOrderNo(), ""));
            if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getState())) {
                throw new CzgException(refund.getMsg());
            } else {
                paymentService.updateChain()
                        .eq(OrderPayment::getId, refPaymentId)
                        .set(OrderPayment::getPayTime, refund.getData().getRefundTime())
                        .set(OrderPayment::getTradeNumber, refund.getData().getRefundOrderId())
                        .set(OrderPayment::getRespJson, JSONObject.toJSONString(refund.getData()))
                        .update();
            }
        }
        ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                .setId(shopUser.getId())
                .setMoney(refPayParam.getRefAmount())
                .setType(0)
                .setRemark("退款")
                .setBizEnum(ShopUserFlowBizEnum.RECHARGE_REFUND)
                .setRelationId(refPaymentId)
                .setRechargeId(inFlow.getId());
        //更新会员余额 并生成流水
        shopUserService.updateMoney(shopUserMoneyEditDTO);
        userFlowService.updateRefund(inFlow.getId(), refPayParam.getRefAmount());
        if (giftFlow != null && (giftFlow.getAmount().subtract(giftFlow.getRefundAmount())).compareTo(BigDecimal.ZERO) > 0) {
            ShopUserMoneyEditDTO giftFlowEdit = new ShopUserMoneyEditDTO()
                    .setId(shopUser.getId())
                    .setMoney(giftFlow.getAmount())
                    .setType(0)
                    .setRemark("退款")
                    .setBizEnum(ShopUserFlowBizEnum.RECHARGE_REFUND)
                    .setRelationId(refPaymentId)
                    .setRechargeId(giftFlow.getId());
            //更新会员余额 并生成流水
            shopUserService.updateMoney(giftFlowEdit);
            userFlowService.updateRefund(giftFlow.getId(), giftFlow.getAmount());
        }
        //移除优惠券
        recordService.remove(QueryWrapper.create()
                .eq(MkShopCouponRecord::getSourceFlowId, inFlow.getId())
                .eq(MkShopCouponRecord::getSource, "activate")
                .eq(MkShopCouponRecord::getStatus, 0));
        return CzgResult.success();
    }

    @Override
    @Transactional
    public CzgResult<Object> refundOrderBefore(OrderInfoRefundDTO param) {
        OrderInfo orderInfo = orderInfoService.getById(param.getOrderId());
        if (orderInfo.getStatus().equals(OrderStatusEnums.CANCELLED.getCode())) {
            throw new CzgException("订单已过期不可退单");
        }
        ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
        Map<String, BigDecimal> returnProMap = new HashMap<>();
        boolean isPay = true;
        String refPayOrderNo = "REFO" + IdUtil.getSnowflakeNextId();
        if (orderInfo.getStatus().equals(OrderStatusEnums.UNPAID.getCode())) {
            isPay = false;
            refPayOrderNo = "";
        }
        if (isPay) {
            if (shopInfo.getIsReturnPwd().equals(1)) {
                AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
                if (!SecureUtil.md5(param.getPwd()).equals(shopInfo.getOperationPwd())) {
                    throw new CzgException("操作密码错误");
                }
            }
            orderInfo.setRefundAmount(orderInfo.getRefundAmount().add(param.getRefundAmount()));
            if (orderInfo.getRefundAmount().compareTo(orderInfo.getPayAmount()) > 0) {
                throw new ValidateException("退单失败，可退金额不足");
            }
        }
        if (CollUtil.isNotEmpty(param.getRefundDetails())) {
            for (OrderDetail refundDetail : param.getRefundDetails()) {
                AssertUtil.isNull(refundDetail.getNum(), "退单数量不能为空");
                //退款数量
                BigDecimal refNum = refundDetail.getNum();
                OrderDetail orderDetail = orderDetailService.getById(refundDetail.getId());
                //可退数量=订单数量-退单数量-退菜数量
                BigDecimal returnNum = orderDetail.getNum().subtract(orderDetail.getRefundNum()).subtract(orderDetail.getReturnNum());
                if (returnNum.compareTo(BigDecimal.ZERO) <= 0 || returnNum.compareTo(refundDetail.getNum()) < 0) {
                    throw new ValidateException("退单失败，" + orderDetail.getProductName() + "可退数量不足");
                }
                if (isPay) {
                    orderDetail.setRefundNum(orderDetail.getRefundNum().add(refNum));
                    if (orderDetail.getNum().compareTo(orderDetail.getRefundNum().add(orderDetail.getReturnNum())) == 0) {
                        orderDetail.setStatus(OrderStatusEnums.REFUND.getCode());
                    } else {
                        orderDetail.setStatus(OrderStatusEnums.PART_REFUND.getCode());
                    }
                } else {
                    orderDetail.setReturnNum(orderDetail.getReturnNum().add(refNum));
                    if (orderDetail.getPackNumber().compareTo(BigDecimal.ZERO) > 0 && orderDetail.getPackNumber().compareTo(orderDetail.getNum().subtract(orderDetail.getReturnNum())) > 0) {
                        orderDetail.setPackNumber(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
                    }
                }
                orderDetail.setRefundNo(refPayOrderNo);
                orderDetail.setRefundRemark(orderDetail.getRefundRemark() + param.getRefundReason());
                if (isPay) {
                    orderDetail.setReturnAmount(refundDetail.getReturnAmount().add(refundDetail.getReturnAmount()));
                    if (orderDetail.getReturnAmount().compareTo(orderDetail.getPayAmount()) > 0) {
                        orderDetail.setReturnAmount(orderDetail.getPayAmount());
                    }
                }
                orderDetailService.updateById(orderDetail);
                if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
                    returnProMap.put(Convert.toStr(orderDetail.getProductId()), refundDetail.getNum());
                }
            }
            long count = orderDetailService.queryChain()
                    .eq(OrderDetail::getOrderId, orderInfo.getId())
                    .ne(OrderDetail::getStatus, OrderStatusEnums.REFUND.getCode()).count();
            if (count > 0 && isPay) {
                orderInfo.setStatus(OrderStatusEnums.PART_REFUND.getCode());
            } else if (isPay) {
                orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
            }
        } else {
            orderInfo.setStatus(OrderStatusEnums.REFUND.getCode());
            // ssss
            List<OrderDetail> orderDetails = orderDetailService.queryChain()
                    .select(OrderDetail::getId, OrderDetail::getProductId, OrderDetail::getNum, OrderDetail::getReturnNum, OrderDetail::getPackAmount, OrderDetail::getReturnNum)
                    .eq(OrderDetail::getOrderId, orderInfo.getId())
                    .list();
            for (OrderDetail orderDetail : orderDetails) {
                if (isPay) {
                    if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
                        returnProMap.put(Convert.toStr(orderDetail.getProductId()), orderDetail.getNum().subtract(orderDetail.getReturnNum()).subtract(orderDetail.getRefundNum()));
                    }
                    orderDetail.setReturnAmount(orderDetail.getPayAmount());
                    orderDetail.setRefundNum(orderDetail.getNum().subtract(orderDetail.getReturnNum()));
                    orderDetail.setStatus(OrderStatusEnums.REFUND.getCode());
                } else {
                    if (orderDetail.getProductId() != null && orderDetail.getProductId() > 0) {
                        returnProMap.put(Convert.toStr(orderDetail.getProductId()), orderDetail.getNum().subtract(orderDetail.getReturnNum()));
                    }
                    orderDetail.setReturnNum(orderDetail.getNum());
                    orderDetail.setStatus(OrderStatusEnums.CANCELLED.getCode());
                }
            }
            orderDetailService.updateBatch(orderDetails);
        }
        //总退款金额
        //TODO 退款 券 未处理
        if (isPay) {
            orderInfo.setRefundType("cash");
            //非现金退款
            if (!param.isCash()) {
                if (orderInfo.getPayType().equals(PayEnums.VIP_PAY.getValue())) {
                    ShopUser shopUser = shopUserService.getShopUserInfo(orderInfo.getShopId(), orderInfo.getUserId());
                    //会员支付 退钱
                    ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
                            .setId(shopUser.getId())
                            .setMoney(param.getRefundAmount())
                            .setType(1)
                            .setRelationId(orderInfo.getId())
                            .setBizEnum(ShopUserFlowBizEnum.ORDER_REFUND);
                    shopUserService.updateMoney(shopUserMoneyEditDTO);
                } else if (orderInfo.getPayType().equals(PayEnums.CREDIT_PAY.getValue())) {
                    AssertUtil.isNull(orderInfo.getCreditBuyerId(), "挂账单退款失败，未查询到挂账人");
                    buyerOrderService.partRefund(orderInfo.getCreditBuyerId().toString(), orderInfo.getId(), param.getRefundAmount());
                } else if (!orderInfo.getPayType().equals(PayEnums.CASH_PAY.getValue())) {
                    //退款 param.getRefundAmount()
                    if (orderInfo.getPayOrderId() == null) {
                        throw new CzgException("退款失败,支付记录不存在");
                    }
                    refundOrder(orderInfo.getShopId(), orderInfo.getId(), orderInfo.getPayOrderId(),
                            refPayOrderNo, StrUtil.isBlank(param.getRefundReason()) ? "退款" : param.getRefundReason(), param.getRefundAmount());
                }
                orderInfo.setRefundType("payBack");
            }
        } else {
            orderInfo.setOrderAmount(orderInfo.getOrderAmount().subtract(param.getRefundAmount()));
        }
        orderInfo.setRefundRemark(orderInfo.getRefundRemark() + param.getRefundReason());
        orderInfoService.updateById(orderInfo);
        //退款返还库存
        if (!returnProMap.isEmpty()) {
            rabbitPublisher.sendOrderRefundMsg(JSONObject.toJSONString(Map.of("orderId", orderInfo.getId(), "returnProMap", returnProMap)));
        }

        // 退款分销还原
        distributionUserService.refund(orderInfo.getId(), orderInfo.getOrderNo());
        return CzgResult.success();
    }

    @Override
    @Transactional
    public void refundOrder(@NonNull Long shopId, @NonNull Long orderId, @NonNull Long payOrderId, @NonNull String refPayOrderNo,
                            @NonNull String refundReason, @NonNull BigDecimal refundAmount) {
        OrderPayment payment = paymentService.getById(payOrderId);
        AssertUtil.isNull(payment, "退款失败支付记录不存在");
        Long refundId = initOrderPayment(new OrderPayment(shopId, orderId, "refund", refPayOrderNo, null, refundAmount));
        CzgResult<CzgRefundResp> refund = refund(shopId, new CzgRefundReq(refPayOrderNo, refundReason, refundAmount.multiply(MONEY_RATE).longValue(),
                payment.getOrderNo(), ""));
        if (refund.getCode() != 200 || refund.getData() == null || !"SUCCESS".equals(refund.getData().getState())) {
            if (refund.getData() != null && refund.getData().getNote() != null) {
                throw new CzgException(refund.getData().getNote());
            }
            throw new CzgException(refund.getMsg());
        } else {
            paymentService.updateChain()
                    .eq(OrderPayment::getId, refundId)
                    .set(OrderPayment::getPayTime, refund.getData().getRefundTime())
                    .set(OrderPayment::getTradeNumber, refund.getData().getRefundOrderId())
                    .set(OrderPayment::getRespJson, JSONObject.toJSONString(refund.getData()))
                    .update();
        }
    }

    @Override
    @Transactional
    public CzgResult<CzgBaseResp> queryPayOrder(@NonNull Long shopId, String payOrderId, String mchOrderNo) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        return czgPayService.queryPayOrder(shopMerchant.getAppId(), shopMerchant.getAppSecret(), payOrderId, mchOrderNo);
    }

    @Override
    @Transactional
    public CzgResult<CzgRefundResp> queryRefund(@NonNull Long shopId, String mchRefundNo, String refundOrderId) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        return czgPayService.queryRefundOrder(shopMerchant.getAppId(), shopMerchant.getAppSecret(), mchRefundNo, refundOrderId);
    }


    private Long initOrderPayment(OrderPayment payment) {
        paymentMapper.insert(payment);
        return payment.getId();
    }

    private void upOrderPayInfo(@NonNull Long orderId, @NonNull PayEnums payType, @NotBlank Long paymentId, String remark) {
        if (paymentId == null) {
            throw new CzgException("未获取到支付记录");
        }
        orderInfoService.updatePayOrderId(orderId, paymentId, payType.getValue(), remark);
    }


    private CzgResult<Map<String, Object>> h5Pay(@NonNull Long shopId, CzgH5PayReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        bizData.assignMerchant(shopMerchant.getStoreId(), shopMerchant.getMerchantName(),
                sysParamsService.getSysParamValue(SysParamCodeEnum.PAY_CZG_NOTIFY_URL.getCode()));
        CzgResult<CzgH5PayResp> h5PayRespCzgResult = czgPayService.h5Pay(shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
        return execPayResult(h5PayRespCzgResult);
    }

    private CzgResult<Map<String, Object>> jsPay(@NonNull Long shopId, @NonNull String payType, CzgJsPayReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        bizData.setSubAppid("aliPay".equals(payType) ? shopMerchant.getAlipaySmallAppid() : shopMerchant.getWechatSmallAppid());
        AssertUtil.isBlank(bizData.getSubAppid(), "暂不可用，请联系商家配置" + ("aliPay".equals(payType) ? "支付宝" : "微信") + "小程序");
        bizData.assignMerchant(shopMerchant.getStoreId(), shopMerchant.getMerchantName(),
                sysParamsService.getSysParamValue(SysParamCodeEnum.PAY_CZG_NOTIFY_URL.getCode()));
        bizData.setPayType("aliPay".equals(payType) ? "ALIPAY" : "WECHAT");
        CzgResult<CzgJsPayResp> jsPayRespCzgResult = czgPayService.jsPay(shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
        return execPayResult(jsPayRespCzgResult);
    }

    public CzgResult<Map<String, Object>> ltPay(@NonNull Long shopId, String payType, CzgLtPayReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        bizData.setSubAppid("aliPay".equals(payType) ? shopMerchant.getAlipaySmallAppid() : shopMerchant.getWechatSmallAppid());
        AssertUtil.isBlank(bizData.getSubAppid(), "暂不可用，请联系商家配置" + ("aliPay".equals(payType) ? "支付宝" : "微信") + "小程序");
        bizData.assignMerchant(shopMerchant.getStoreId(), shopMerchant.getMerchantName(),
                sysParamsService.getSysParamValue(SysParamCodeEnum.PAY_CZG_NOTIFY_URL.getCode()));
        CzgResult<CzgLtPayResp> ltPayRespCzgResult = czgPayService.ltPay(shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
        return execPayResult(ltPayRespCzgResult);
    }

    private CzgResult<Map<String, Object>> scanPay(@NonNull Long shopId, CzgScanPayReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        bizData.assignMerchant(shopMerchant.getStoreId(), shopMerchant.getMerchantName(),
                sysParamsService.getSysParamValue(SysParamCodeEnum.PAY_CZG_NOTIFY_URL.getCode()));
        CzgResult<CzgScanPayResp> scanPayRespCzgResult = czgPayService.scanPay(shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
        return execPayResult(scanPayRespCzgResult);
    }

    private CzgResult<Map<String, Object>> microPay(@NonNull Long shopId, CzgMicroPayReq bizData) {
        AssertUtil.isBlank(bizData.getAuthCode(), "扫码失败，请重试");
        if (bizData.getAuthCode().length() > 26) {
            throw new CzgException("支付失败，不支持的条码");
        }
        ShopMerchant shopMerchant = getMerchant(shopId);
        bizData.assignMerchant(shopMerchant.getStoreId(), shopMerchant.getMerchantName(),
                sysParamsService.getSysParamValue(SysParamCodeEnum.PAY_CZG_NOTIFY_URL.getCode()));
        String firstTwoDigitsStr = bizData.getAuthCode().substring(0, 2);
        // 将截取的字符串转换为整数
        int firstTwoDigits = Integer.parseInt(firstTwoDigitsStr);
        // 判断范围
        if (firstTwoDigits >= 10 && firstTwoDigits <= 15) {
            //微信支付
            bizData.setSubAppid(shopMerchant.getWechatSmallAppid());
        } else if (firstTwoDigits >= 25 && firstTwoDigits <= 30) {
            //支付宝支付
            bizData.setSubAppid(shopMerchant.getAlipaySmallAppid());
        } else {
            throw new ValidateException("扫描码非法或暂不支持");
        }
        CzgResult<CzgMicroPayResp> czgScanPayResult = czgPayService.microPay(shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);

        return execPayResult(czgScanPayResult);
    }

    private CzgResult<CzgRefundResp> refund(@NonNull Long shopId, CzgRefundReq bizData) {
        ShopMerchant shopMerchant = getMerchant(shopId);
        bizData.setNotifyUrl(sysParamsService.getSysParamValue(SysParamCodeEnum.PAY_CZG_REFUND_NOTIFY_URL.getCode()));
        return czgPayService.refundOrder(shopMerchant.getAppId(), shopMerchant.getAppSecret(), bizData);
    }

    private ShopMerchant getMerchant(Long shopId) {
        try {
            return shopMerchantService.getById(shopId);
        } catch (Exception e) {
            throw new CzgException("暂未开通支付");
        }
    }

    private CzgResult<Map<String, Object>> execPayResult(CzgResult<? extends CzgBaseResp> res) {
        CzgResult<Map<String, Object>> result = CzgResult.success();
        if (res.getCode() != 200 || res.getData() == null) {
            result.setCode(500);
            result.setMsg(res.getMsg());
            return result;
        }

        CzgBaseResp data = res.getData();

        Map<String, Object> map = new HashMap<>();
        switch (data) {
            case CzgMicroPayResp ignored -> {
                if ("TRADE_SUCCESS".equals(data.getState())) {
                    return result;
                } else if ("TRADE_AWAIT".equals(data.getState())) {
                    result.setCode(CzgRespCode.WAIT_PAY.getCode());
                    result.setMsg("等待用户付款");
                } else {
                    result.setCode(CzgRespCode.FAILURE.getCode());
                }
            }
            case CzgH5PayResp h5PayResp ->
                    map = JSONObject.parseObject(JSONObject.toJSONString(h5PayResp.getPayInfo()));
            case CzgJsPayResp jsPayResp ->
                    map = JSONObject.parseObject(JSONObject.toJSONString(jsPayResp.getPayInfo()));
            case CzgLtPayResp ltPayResp ->
                    map = JSONObject.parseObject(JSONObject.toJSONString(ltPayResp.getPayInfo()));
            case CzgScanPayResp scanPayResp ->
                    map = JSONObject.parseObject(JSONObject.toJSONString(scanPayResp.getPayInfo()));
            default -> throw new IllegalStateException("Unexpected value: " + data);
        }

        result.setData(map);

        return result;
    }
}
