package com.yc.ship.module.trade.service.pay.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yc.ship.framework.common.exception.ServiceException;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.json.JsonUtils;
import com.yc.ship.framework.common.util.object.ObjectUtils;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.util.TenantUtils;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.ota.api.OtaDistributorApi;
import com.yc.ship.module.ota.api.dto.BillPayReqDTO;
import com.yc.ship.module.ota.api.dto.DistributorRechargeReqDTO;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.ota.api.dto.DistributorSelfRechargeReqDTO;
import com.yc.ship.module.product.api.VoyageApi;
import com.yc.ship.module.product.api.dto.OrderRoomUseDTO;
import com.yc.ship.module.product.api.dto.ReduceStockReqDTO;
import com.yc.ship.module.product.enums.DistributorOrStoreEnum;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderReqVO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.PayOrderRespVO;
import com.yc.ship.module.trade.dal.dataobject.order.*;
import com.yc.ship.module.trade.dal.dataobject.supplier.TradeSupplierOrderDO;
import com.yc.ship.module.trade.dal.mysql.order.TradeOrderLogMapper;
import com.yc.ship.module.trade.dal.mysql.order.TradeOrderMapper;
import com.yc.ship.module.trade.dal.mysql.order.TradeOrderTotalMapper;
import com.yc.ship.module.trade.dal.mysql.order.TradeVisitorMapper;
import com.yc.ship.module.trade.enums.*;
import com.yc.ship.module.trade.framework.annotation.TradeOrderLog;
import com.yc.ship.module.trade.framework.common.ExceptionUtils;
import com.yc.ship.module.trade.framework.common.TradeOrderLogUtils;
import com.yc.ship.module.trade.service.bill.BillService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import com.yc.ship.module.trade.service.pay.PayPlatService;
import com.yc.ship.module.trade.service.pay.PayTypeService;
import com.yc.ship.module.trade.service.pay.TradeOrderPayService;
import com.yc.ship.module.trade.service.pay.bo.PayNotifyReqBO;
import com.yc.ship.module.trade.service.refund.TradeRefundService;
import com.yc.ship.module.trade.service.supplier.TradeSupplierCallbackService;
import com.yc.ship.module.trade.service.supplier.TradeSupplierOrderRepositoryService;
import com.yc.ship.module.trade.service.supplier.TradeSupplierService;
import com.yc.ship.module.trade.utils.AgencyAuthUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.yc.ship.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
import static com.yc.ship.module.trade.enums.ApiConstants.*;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.*;
import static com.yc.ship.module.trade.service.order.TradeOrderService.UPDATE_ORDER_LOCK;
import static com.yc.ship.module.trade.service.pay.impl.PayPlatServiceImpl.SUCCESS;


/**
 * &#064;Description ：订单支付service实现
 * &#064;Author ：qsl
 * &#064;Date ：2025/6/4 16:18
 *
 * @author qsl
 */
@Service
@Slf4j
public class TradeOrderPayServiceImpl implements TradeOrderPayService {

    @Resource
    private TradeOrderRepositoryService tradeOrderRepositoryService;
    @Resource
    private TradeSupplierService tradeSupplierService;
    @Resource
    private TradeSupplierCallbackService tradeSupplierCallbackService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private Map<String, PayTypeService> payTypeServiceMap;
    @Resource
    private PayPlatService payPlatService;
    @Resource
    @Lazy
    private ConfigApi configApi;
    @Resource
    private TradeSupplierOrderRepositoryService tradeSupplierOrderRepositoryService;
    @Resource
    @Lazy
    private OtaDistributorApi otaDistributorApi;
    @Resource
    private TradeRefundService tradeRefundService;
    @Resource
    private BillService billService;
    @Resource
    private AgencyAuthUtils agencyAuthUtils;

    @Resource
    private VoyageApi voyageApi;

    @Resource
    private TradeOrderTotalMapper tradeOrderTotalMapper;
    @Resource
    private TradeVisitorMapper tradeVisitorMapper;

    @Resource
    private TradeOrderMapper tradeOrderMapper;

    @Resource
    private TradeOrderLogMapper tradeOrderLogMapper;

    @Override
    public CommonResult<PayOrderRespVO> payOrder(PayOrderReqVO payOrderReqVO) {
        try {
            Long orderId = payOrderReqVO.getOrderId();
            String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
            RLock lock = redissonClient.getLock(lockKey);
            try {
                if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                    //1.获取订单信息
                    TradeOrderDO tradeOrder = tradeOrderRepositoryService.getById(payOrderReqVO.getOrderId());
                    if (tradeOrder == null) {
                        Asserts.isTrue(false, "订单不存在");
                    } else {
                        if (payOrderReqVO.getAccountId() == null && tradeOrder.getSourceId() != null) {
                            payOrderReqVO.setAccountId(tradeOrder.getSourceId());
                        }
                        if (ObjectUtil.equal(tradeOrder.getPayStatus(), PaymentStatusEnum.PAID.getStatus())) {
                            //重复支付
                            return doRePayOrder(tradeOrder);
                        } else {
                            validate(tradeOrder, payOrderReqVO);
                            //2.创建支付交易单
                            TradeOrderPayDO tradeOrderPayDO = buildOrderPay(tradeOrder, payOrderReqVO);
                            payOrderReqVO.setStoreId(tradeOrder.getStoreId());
                            tradeOrderRepositoryService.savePayOrder(tradeOrderPayDO);
                            payOrderReqVO.setAccountName(tradeOrder.getSourceName());
                            return doPayOrder(tradeOrderPayDO, payOrderReqVO);
                        }
                    }
                } else {
                    log.error("订单支付失败，未获取到锁。orderId:{}", orderId);
                    return CommonResult.error(GET_LOCK_EXCEPTION);
                }
            } finally {
                if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                    lock.unlock();
                }
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "下单支付失败:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("下单支付失败：", e);
            return CommonResult.error(ORDER_PAY_FAIL);
        }
        return CommonResult.error(ORDER_PAY_FAIL);
    }

    @Override
    public CommonResult<PayOrderRespVO> payDeposiOrder(PayOrderReqVO payOrderReqVO) {
        try {
            Long orderId = payOrderReqVO.getOrderId();
            String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
            RLock lock = redissonClient.getLock(lockKey);
            try {
                if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                    //1.获取订单信息
                    TradeOrderDO tradeOrder = tradeOrderRepositoryService.getById(payOrderReqVO.getOrderId());
                    if (tradeOrder == null) {
                        Asserts.isTrue(false, "订单不存在");
                    } else {
                        if (payOrderReqVO.getAccountId() == null && tradeOrder.getSourceId() != null) {
                            payOrderReqVO.setAccountId(tradeOrder.getSourceId());
                        }
                        if (ObjectUtil.equal(tradeOrder.getDeposiStatus(), 2)) {
                            //重复支付
                            Asserts.isTrue(false, "定金已支付，不要重复操作");
                        } else {
                            //2.创建定金支付交易单
                            payOrderReqVO.setPayAmount(tradeOrder.getDeposi());
                            TradeOrderPayDO tradeOrderPayDO = buildOrderPay(tradeOrder, payOrderReqVO);
                            tradeOrderPayDO.setOrderType(PAY_ORDER_TYPE_DEPOSI);
                            payOrderReqVO.setStoreId(tradeOrder.getStoreId());
                            tradeOrderRepositoryService.savePayOrder(tradeOrderPayDO);
                            payOrderReqVO.setAccountName(tradeOrder.getSourceName());
                            return doDeposiPayOrder(tradeOrderPayDO, payOrderReqVO);
                        }
                    }
                } else {
                    log.error("订单支付失败，未获取到锁。orderId:{}", orderId);
                    return CommonResult.error(GET_LOCK_EXCEPTION);
                }
            } finally {
                if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                    lock.unlock();
                }
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "下单支付失败:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("下单支付失败：", e);
            return CommonResult.error(ORDER_PAY_FAIL);
        }
        return CommonResult.error(ORDER_PAY_FAIL);
    }

    @Override
    public CommonResult<PayOrderRespVO> payBcOrder(PayOrderReqVO payOrderReqVO) {
        try {
            Long orderId = payOrderReqVO.getOrderId();
            String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
            RLock lock = redissonClient.getLock(lockKey);
            try {
                if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                    //1.获取订单信息
                    TradeOrderDO tradeOrder = tradeOrderRepositoryService.getById(payOrderReqVO.getOrderId());
                    if (tradeOrder == null) {
                        Asserts.isTrue(false, "订单不存在");
                    } else {
                        if (payOrderReqVO.getAccountId() == null && tradeOrder.getSourceId() != null) {
                            payOrderReqVO.setAccountId(tradeOrder.getSourceId());
                        }
                        if (ObjectUtil.equal(tradeOrder.getIsSupplementary(), 2)) {
                            //重复支付
                            Asserts.isTrue(false, "补差价已支付，不要重复操作");
                        } else {
                            //2.创建定金支付交易单
                            payOrderReqVO.setPayAmount(tradeOrder.getSupplementAmount().abs());
                            TradeOrderPayDO tradeOrderPayDO = buildOrderPay(tradeOrder, payOrderReqVO);
                            tradeOrderPayDO.setOrderType(PAY_ORDER_TYPE_BC);
                            payOrderReqVO.setStoreId(tradeOrder.getStoreId());
                            tradeOrderRepositoryService.savePayOrder(tradeOrderPayDO);
                            payOrderReqVO.setAccountName(tradeOrder.getSourceName());
                            return doBcPayOrder(tradeOrderPayDO, payOrderReqVO);
                        }
                    }
                } else {
                    log.error("订单支付失败，未获取到锁。orderId:{}", orderId);
                    return CommonResult.error(GET_LOCK_EXCEPTION);
                }
            } finally {
                if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                    lock.unlock();
                }
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "下单支付失败:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("下单支付失败：", e);
            return CommonResult.error(ORDER_PAY_FAIL);
        }
        return CommonResult.error(ORDER_PAY_FAIL);
    }

    @Override
    public CommonResult<?> handlePayNotify(Map<String, Object> map) {
        PayNotifyReqBO payNotifyReqSourceBO = new PayNotifyReqBO();
        final PayNotifyReqBO payNotifyReqBO = BeanUtil.fillBeanWithMap(map, payNotifyReqSourceBO, false);
        String lockKey = String.format(UPDATE_PAY_ORDER_LOCK, Long.parseLong(payNotifyReqBO.getMchOrderNo()));
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeOrderPayDO tradeOrderPayDO = tradeOrderRepositoryService.getPayOrderByIdIgnoreTenant(Long.parseLong(payNotifyReqBO.getMchOrderNo()));
                //如果支付单已经变为已支付，订单有无效需要自动退，又没有退的时候，就需要把支付单状态改为0，重新推通知
                if (ObjectUtils.equalsAny(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.PAID.getStatus(), PaymentStatusEnum.AUTO_REFUND.getStatus())) {
                    //返回成功，让支付平台无需再推通知
                    return CommonResult.success(null);
                }
                Asserts.isTrue(ObjectUtils.equalsAny(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.INIT.getStatus(), PaymentStatusEnum.UNPAID.getStatus()), "支付单{}当前状态不可更改{}", payNotifyReqBO.getMchOrderNo(), tradeOrderPayDO.getPayStatus());
                TenantUtils.execute(tradeOrderPayDO.getTenantId(), () -> {
                    if (StrUtil.isBlank(tradeOrderPayDO.getPaymentNo())) {
                        tradeOrderPayDO.setPaymentNo(payNotifyReqBO.getPayOrderId());
                    }
                    //银行账单号
                    tradeOrderPayDO.setBillNo(payNotifyReqBO.getBillNo());
                    tradeOrderPayDO.setPosNo(payNotifyReqBO.getChannelOrderNo());
                    //同步银行返回的支付时间
                    if (StrUtil.isNotBlank(payNotifyReqBO.getBillDate())) {
                        try {
                            tradeOrderPayDO.setPaymentDate(DateUtil.parseLocalDateTime(payNotifyReqBO.getBillDate(), DatePattern.PURE_DATETIME_PATTERN));
                        } catch (Exception e) {
                            log.error("支付平台返回的支付时间转换错误{}", payNotifyReqBO.getBillDate());
                        }
                    }

                    afterPaySuccess(tradeOrderPayDO);
                });
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "支付通知处理异常:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("支付通知处理异常:{}", payNotifyReqBO.getMchOrderNo(), e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return CommonResult.success(null);
    }

    @Override
    public CommonResult<?> handleDeposiPayNotify(Map<String, Object> map) {
        PayNotifyReqBO payNotifyReqSourceBO = new PayNotifyReqBO();
        final PayNotifyReqBO payNotifyReqBO = BeanUtil.fillBeanWithMap(map, payNotifyReqSourceBO, false);
        String lockKey = String.format(UPDATE_PAY_ORDER_LOCK, Long.parseLong(payNotifyReqBO.getMchOrderNo()));
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeOrderPayDO tradeOrderPayDO = tradeOrderRepositoryService.getPayOrderByIdIgnoreTenant(Long.parseLong(payNotifyReqBO.getMchOrderNo()));
                //如果支付单已经变为已支付，订单有无效需要自动退，又没有退的时候，就需要把支付单状态改为0，重新推通知
                if (ObjectUtils.equalsAny(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.PAID.getStatus(), PaymentStatusEnum.AUTO_REFUND.getStatus())) {
                    //返回成功，让支付平台无需再推通知
                    return CommonResult.success(null);
                }
                Asserts.isTrue(ObjectUtils.equalsAny(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.INIT.getStatus(), PaymentStatusEnum.UNPAID.getStatus()), "支付单{}当前状态不可更改{}", payNotifyReqBO.getMchOrderNo(), tradeOrderPayDO.getPayStatus());
                TenantUtils.execute(tradeOrderPayDO.getTenantId(), () -> {
                    if (StrUtil.isBlank(tradeOrderPayDO.getPaymentNo())) {
                        tradeOrderPayDO.setPaymentNo(payNotifyReqBO.getPayOrderId());
                    }
                    //银行账单号
                    tradeOrderPayDO.setBillNo(payNotifyReqBO.getBillNo());
                    tradeOrderPayDO.setPosNo(payNotifyReqBO.getChannelOrderNo());
                    //同步银行返回的支付时间
                    if (StrUtil.isNotBlank(payNotifyReqBO.getBillDate())) {
                        try {
                            tradeOrderPayDO.setPaymentDate(DateUtil.parseLocalDateTime(payNotifyReqBO.getBillDate(), DatePattern.PURE_DATETIME_PATTERN));
                        } catch (Exception e) {
                            log.error("支付平台返回的支付时间转换错误{}", payNotifyReqBO.getBillDate());
                            tradeOrderPayDO.setPaymentDate(LocalDateTime.now());
                        }
                    }
                    TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(tradeOrderPayDO.getOrderId());
                    //验证订单是否已全部支付完成
                    BigDecimal hadPayAmount = tradeOrderRepositoryService.getHadPayAmount(tradeOrderPayDO.getOrderId());
                    if (hadPayAmount.compareTo(tradeOrderDO.getAmount()) >= 0) {
                        log.error("计算订单全部支付金额：{},订单金额：{}", hadPayAmount, tradeOrderDO.getAmount());
                        tradeOrderDO.setOrderStatus(TradeOrderStatusEnum.UNUSED.getStatus());
                    }
                    //更新支付单状态
                    updatePayOrderSuccess(tradeOrderPayDO);
                    //4.1支付成功
                    updateDeposiOrderPaid(tradeOrderDO, tradeOrderPayDO);
                });
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "支付通知处理异常:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("支付通知处理异常:{}", payNotifyReqBO.getMchOrderNo(), e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return CommonResult.success(null);
    }

    @Override
    public CommonResult<?> handleBcPayNotify(Map<String, Object> map) {
        PayNotifyReqBO payNotifyReqSourceBO = new PayNotifyReqBO();
        final PayNotifyReqBO payNotifyReqBO = BeanUtil.fillBeanWithMap(map, payNotifyReqSourceBO, false);
        String lockKey = String.format(UPDATE_PAY_ORDER_LOCK, Long.parseLong(payNotifyReqBO.getMchOrderNo()));
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeOrderPayDO tradeOrderPayDO = tradeOrderRepositoryService.getPayOrderByIdIgnoreTenant(Long.parseLong(payNotifyReqBO.getMchOrderNo()));
                //如果支付单已经变为已支付，订单有无效需要自动退，又没有退的时候，就需要把支付单状态改为0，重新推通知
                if (ObjectUtils.equalsAny(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.PAID.getStatus(), PaymentStatusEnum.AUTO_REFUND.getStatus())) {
                    //返回成功，让支付平台无需再推通知
                    return CommonResult.success(null);
                }
                Asserts.isTrue(ObjectUtils.equalsAny(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.INIT.getStatus(), PaymentStatusEnum.UNPAID.getStatus()), "支付单{}当前状态不可更改{}", payNotifyReqBO.getMchOrderNo(), tradeOrderPayDO.getPayStatus());
                TenantUtils.execute(tradeOrderPayDO.getTenantId(), () -> {
                    if (StrUtil.isBlank(tradeOrderPayDO.getPaymentNo())) {
                        tradeOrderPayDO.setPaymentNo(payNotifyReqBO.getPayOrderId());
                    }
                    //银行账单号
                    tradeOrderPayDO.setBillNo(payNotifyReqBO.getBillNo());
                    tradeOrderPayDO.setPosNo(payNotifyReqBO.getChannelOrderNo());
                    //同步银行返回的支付时间
                    if (StrUtil.isNotBlank(payNotifyReqBO.getBillDate())) {
                        try {
                            tradeOrderPayDO.setPaymentDate(DateUtil.parseLocalDateTime(payNotifyReqBO.getBillDate(), DatePattern.PURE_DATETIME_PATTERN));
                        } catch (Exception e) {
                            log.error("支付平台返回的支付时间转换错误{}", payNotifyReqBO.getBillDate());
                            tradeOrderPayDO.setPaymentDate(LocalDateTime.now());
                        }
                    }
                    TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(tradeOrderPayDO.getOrderId());
                    //更新支付单状态
                    updatePayOrderSuccess(tradeOrderPayDO);
                    //4.1支付成功
                    updateBcOrderPaid(tradeOrderDO, tradeOrderPayDO);
                });
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "支付通知处理异常:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("支付通知处理异常:{}", payNotifyReqBO.getMchOrderNo(), e);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }

        return CommonResult.success(null);
    }

    @Override
    @TenantIgnore
    public CommonResult<?> payOrderQuery(Long payOrderId) {
        TradeOrderPayDO tradeOrderPayDO = tradeOrderRepositoryService.getPayOrderById(payOrderId);
        Integer code = tradeOrderPayDO.getPayStatus();
        if (ObjectUtil.equal(tradeOrderPayDO.getPayStatus(), PaymentStatusEnum.INIT.getStatus())) {
            //支付平台查询
            if (StrUtil.isNotBlank(tradeOrderPayDO.getPaymentNo())) {
                TradeMchInfoDO tradeMchInfoDO = tradeOrderRepositoryService.getByMchId(tradeOrderPayDO.getMerchantNo());
                JSONObject map = payPlatService.payOrderQuery(tradeOrderPayDO, tradeMchInfoDO);
                if (StrUtil.equals(SUCCESS, MapUtils.getString(map, "retCode")) && StrUtil.equals(SUCCESS, MapUtils.getString(map, "resCode"))) {
                    //支付成功，正常情况支付平台会异步通知业务系统，那里会变更订单状态,暂时不处理，
                    code = 8888;
                } else if (StrUtil.equals("lunxun", MapUtils.getString(map, "resCode"))) {
                    //轮询，支付状态未知
                    code = PaymentStatusEnum.INIT.getStatus();
                } else if (StrUtil.equals("notpay", MapUtils.getString(map, "resCode"))) {
                    //未支付，银行返回的未支付
                    tradeOrderPayDO.setPayStatus(PaymentStatusEnum.UNPAID.getStatus());
                    tradeOrderRepositoryService.updatePayOrderStatus(tradeOrderPayDO);
                    code = PaymentStatusEnum.UNPAID.getStatus();
                }
            }
        }
        return CommonResult.success(code);
    }

    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.PAY_TIMEOUT_SYSTEM_CANCEL)
    public CommonResult<?> orderPayTimeOutMessageHandler(Long orderId, Boolean isManual) {
        String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(orderId);
                if (tradeOrderDO == null) {
                    //订单合并了，原订单不存在
                    return CommonResult.success(null);
                }
                Integer orderStatus = tradeOrderDO.getOrderStatus();
                Asserts.isTrue(ObjectUtils.equalsAny(tradeOrderDO.getOrderStatus(), TradeOrderStatusEnum.UNPAID.getStatus(), TradeOrderStatusEnum.INIT.getStatus(), TradeOrderStatusEnum.PAYING.getStatus(), TradeOrderStatusEnum.YD.getStatus()), 31000, "当前状态已变更不能取消订单{},状态{}", orderId, tradeOrderDO.getOrderStatus());
                //变更订单为取消
                tradeOrderDO.setOrderStatus(TradeOrderStatusEnum.CANCELED.getStatus());
                tradeOrderRepositoryService.cancelOrder(tradeOrderDO.getId());
                //添加订单日志
                TradeOrderLogUtils.setOrderInfo(orderId, orderStatus, TradeOrderStatusEnum.CANCELED.getStatus());
            } else {
                log.error("订单支付更新失败，未获取到锁。orderId:{}", orderId);
                return CommonResult.error(GET_LOCK_EXCEPTION);
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "订单支付超时处理:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("订单更新异常orderId:{}", orderId, e);
            return CommonResult.error(UNKNOWN_EXCEPTION);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return CommonResult.success(null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MANUL_CANCEL)
    public CommonResult<?> orderPayCancelHandler(Long orderId) {
        String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(orderId);
                if (tradeOrderDO == null) {
                    //订单合并了，原订单不存在
                    return CommonResult.success(null);
                }
                Integer orderStatus = tradeOrderDO.getOrderStatus();
                Asserts.isTrue(ObjectUtils.equalsAny(tradeOrderDO.getOrderStatus(), TradeOrderStatusEnum.UNPAID.getStatus(), TradeOrderStatusEnum.INIT.getStatus(), TradeOrderStatusEnum.PAYING.getStatus(), TradeOrderStatusEnum.YD.getStatus(), TradeOrderStatusEnum.CANCEL_AUDIT.getStatus()), 31000, "当前状态已变更不能取消订单{},状态{}", orderId, tradeOrderDO.getOrderStatus());
                //变更订单为取消
                tradeOrderDO.setOrderStatus(TradeOrderStatusEnum.CANCELED.getStatus());
                tradeOrderRepositoryService.cancelOrder(tradeOrderDO.getId());
                ReduceStockReqDTO reqDTO = new ReduceStockReqDTO();
                reqDTO.setOrderId(tradeOrderDO.getId());
                reqDTO.setOrderStatus(tradeOrderDO.getOrderStatus());
                //TODO: 当前默认为分销商，扣分销商库存，门店的后续再完善
                reqDTO.setType(DistributorOrStoreEnum.DISTRIBUTOR.getValue());
                reqDTO.setVoyageId(tradeOrderDO.getVoyageId());
                reqDTO.setDistributorId(Long.valueOf(tradeOrderDO.getSourceId()));
                reqDTO.setStoreId(tradeOrderDO.getStoreId());

                TradeOrderTotalDO tradeOrderTotal = tradeOrderTotalMapper.selectOne(new LambdaQueryWrapper<TradeOrderTotalDO>().eq(TradeOrderTotalDO::getOldOrderId, orderId));
                reqDTO.setUseRoomNum(BigDecimal.valueOf(tradeOrderTotal.getUseRoomTotalNum()));

                List<TradeVisitorDO> tradeDetailDOList = tradeVisitorMapper.selectShipVisitor(orderId);
                List<OrderRoomUseDTO> orderRoomUseDTOList = new ArrayList<>();
                Map<String, Long> collect = tradeDetailDOList.stream().filter(tradeVisitorDO -> tradeVisitorDO.getRoomId() != null).collect(Collectors.groupingBy(TradeVisitorDO::getRoomId, Collectors.counting()));
                collect.keySet().forEach(roomId -> {
                    if (StringUtils.isNotBlank(roomId)) {
                        OrderRoomUseDTO orderRoomUseDTO = new OrderRoomUseDTO();
                        orderRoomUseDTO.setRoomId(Long.valueOf(roomId));
                        orderRoomUseDTO.setNum(BigDecimal.valueOf(collect.get(roomId)).divide(new BigDecimal(2)));
                        orderRoomUseDTOList.add(orderRoomUseDTO);
                    }
                });
                reqDTO.setOrderRoomList(orderRoomUseDTOList);
                if (Objects.equals(orderStatus, TradeOrderStatusEnum.YD.getStatus())) {
                    voyageApi.preCancelReduceStock(reqDTO);
                } else {
                    voyageApi.cancelReduceStock(reqDTO);
                }

                //添加订单日志
                TradeOrderLogUtils.setOrderInfo(orderId, orderStatus, TradeOrderStatusEnum.CANCELED.getStatus());
            } else {
                log.error("订单支付取消更新失败，未获取到锁。orderId:{}", orderId);
                return CommonResult.error(GET_LOCK_EXCEPTION);
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "订单取消超时处理:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("订单取消更新异常orderId:{}", orderId, e);
            return CommonResult.error(UNKNOWN_EXCEPTION);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return CommonResult.success(null);
    }

    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.MANUL_CANCEL)
    public CommonResult<?> cancelOrder(Long orderId) {
        return orderPayCancelHandler(orderId);
    }

    @Override
    public CommonResult<?> retryPaySupplierOrder(Long orderId, Long supplierOrderId) {

        String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
        RLock lock = redissonClient.getLock(lockKey);
        CommonResult<?> result;
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(orderId);
                Asserts.isTrue(ObjectUtil.equal(tradeOrderDO.getOrderStatus(), TradeOrderStatusEnum.PROCESS_FAIL.getStatus()), "订单状态已变更不能更新{}", tradeOrderDO.getOrderStatus());

                if (supplierOrderId == null) {
                    //根据订单批量重试供应商订单
                    List<TradeSupplierOrderDO> tradeSupplierOrderDOList = tradeSupplierOrderRepositoryService.getUnPaySuccessOrder(orderId);
                    if (CollUtil.isNotEmpty(tradeSupplierOrderDOList)) {
                        for (TradeSupplierOrderDO tradeSupplierOrderDO : tradeSupplierOrderDOList) {
                            result = tradeSupplierService.retryPayOrder(tradeSupplierOrderDO.getId());
                            if (result.isError()) {
                                return result;
                            }
                        }
                    }
                } else {
                    //根据供应商订单单独重试
                    result = tradeSupplierService.retryPayOrder(supplierOrderId);
                    if (result.isError()) {
                        return result;
                    }
                }
                //全部供应商出票成功，则变更订单状态
                Map<String, Long> data = tradeSupplierOrderRepositoryService.getSupplierOrderSuccessCount(orderId);
                if (ObjectUtil.equal(data.get("totalCount"), data.get("successCount"))) {
                    tradeSupplierCallbackService.afterAllOrderPay(tradeOrderDO);
                }
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "订单更新异常orderId:" + orderId, e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("订单更新异常orderId:{}", orderId, e);
            return CommonResult.error(UNKNOWN_EXCEPTION);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return CommonResult.success(null);
    }

    @Override
    public CommonResult<PayOrderRespVO> payOuterOrder(PayOrderReqVO payOrderReqVO) {
        //创建支付单
        Asserts.isTrue(payOrderReqVO.getPaySource() != null, "支付来源不能为空");
        TradeOrderPayDO tradeOrderPayDO = new TradeOrderPayDO();
        tradeOrderPayDO.setId(IdWorker.getId());
        tradeOrderPayDO.setOrderId(payOrderReqVO.getOrderId());
        tradeOrderPayDO.setPayStatus(PaymentStatusEnum.INIT.getStatus());
        tradeOrderPayDO.setSellMethod(payOrderReqVO.getPaySource());
        tradeOrderPayDO.setPayAmount(payOrderReqVO.getPayAmount());
        tradeOrderPayDO.setPaymentType(payOrderReqVO.getPayType());
        tradeOrderPayDO.setRefundAmount(BigDecimal.ZERO);
        tradeOrderPayDO.setOrderType(PAY_ORDER_TYPE_OTHER);

        Long orderId = payOrderReqVO.getOrderId();
        String lockKey = String.format(UPDATE_PAY_OUTER_ORDER_LOCK, payOrderReqVO.getPaySource(), orderId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                //验证当前订单是否可以支付
                canPayByCheckOuterOrderId(tradeOrderPayDO, payOrderReqVO);

                tradeOrderRepositoryService.savePayOrder(tradeOrderPayDO);

                return doPayOrder(tradeOrderPayDO, payOrderReqVO);
            } else {
                log.error("支付失败，未获取到锁。orderId:{}", orderId);
                return CommonResult.error(GET_LOCK_EXCEPTION);
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "外部订单支付失败:", e);
            return CommonResult.error(e);
        } catch (Exception e) {
            log.error("外部订单支付失败：", e);
            return CommonResult.error(ORDER_PAY_FAIL);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private CommonResult<PayOrderRespVO> doRePayOrder(TradeOrderDO tradeOrderDO) {

        List<TradeOrderPayDO> orderPayList = tradeOrderRepositoryService.getOrderPayList(tradeOrderDO.getId());
        PayOrderRespVO payOrderRespVO = new PayOrderRespVO().setOrderPayId(orderPayList.get(0).getId()).setOrderId(tradeOrderDO.getId());
        if (ObjectUtil.equal(tradeOrderDO.getOrderStatus(), TradeOrderStatusEnum.PROCESS_FAIL.getStatus())) {
            //如果出票失败，再次发起
            //向供应商出票
            CommonResult<?> result = retryPaySupplierOrder(tradeOrderDO.getId(), null);
            if (result.isError()) {
                return CommonResult.error(result);
            }
        }
        return CommonResult.success(payOrderRespVO);
    }

    private CommonResult<PayOrderRespVO> doPayOrder(TradeOrderPayDO tradeOrderPayDO, PayOrderReqVO payOrderReqVO) {
        PayOrderRespVO payOrderRespVO = new PayOrderRespVO().setOrderPayId(tradeOrderPayDO.getId()).setOrderId(tradeOrderPayDO.getOrderId());

        if (needPayPlatCreateOrder(payOrderReqVO, tradeOrderPayDO)) {
            //3.调用支付平台，其结果不用于更新订单状态，需要通过支付查询或者异步通知变更订单状态
            Map result = usePayPlatCreatePayOrder(payOrderReqVO, tradeOrderPayDO);
            payOrderRespVO.setPayPlatResult(result);
            if (result != null) {
                tradeOrderPayDO.setPayParams(JsonUtils.toJsonString(result));
            }
            tradeOrderRepositoryService.updatePayOrderPayParams(tradeOrderPayDO);
        } else {
            //4.其他支付方式
            String tradeId = useOtherPayType(payOrderReqVO, tradeOrderPayDO);
            tradeOrderPayDO.setPaymentNo(tradeId);
            //4.1支付成功
            CommonResult<?> result = afterPaySuccessWithHeldLock(tradeOrderPayDO);
            if (result.isError()) {
                return CommonResult.error(result);
            }

        }
        return CommonResult.success(payOrderRespVO);
    }

    private CommonResult<PayOrderRespVO> doDeposiPayOrder(TradeOrderPayDO tradeOrderPayDO, PayOrderReqVO payOrderReqVO) {
        PayOrderRespVO payOrderRespVO = new PayOrderRespVO().setOrderPayId(tradeOrderPayDO.getId()).setOrderId(tradeOrderPayDO.getOrderId());

        if (needPayPlatCreateOrder(payOrderReqVO, tradeOrderPayDO)) {
            //3.调用支付平台，其结果不用于更新订单状态，需要通过支付查询或者异步通知变更订单状态
            Map result = useDeposiPayPlatCreatePayOrder(payOrderReqVO, tradeOrderPayDO);
            payOrderRespVO.setPayPlatResult(result);
            if (result != null) {
                tradeOrderPayDO.setPayParams(JsonUtils.toJsonString(result));
            }
            tradeOrderRepositoryService.updatePayOrderPayParams(tradeOrderPayDO);
        } else {
            //4.其他支付方式
            String tradeId = useOtherPayType(payOrderReqVO, tradeOrderPayDO);
            tradeOrderPayDO.setPaymentNo(tradeId);
            //4.1支付成功
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(payOrderReqVO.getOrderId());
            updateDeposiOrderPaid(tradeOrderDO, tradeOrderPayDO);
        }
        return CommonResult.success(payOrderRespVO);
    }

    private CommonResult<PayOrderRespVO> doBcPayOrder(TradeOrderPayDO tradeOrderPayDO, PayOrderReqVO payOrderReqVO) {
        PayOrderRespVO payOrderRespVO = new PayOrderRespVO().setOrderPayId(tradeOrderPayDO.getId()).setOrderId(tradeOrderPayDO.getOrderId());

        if (needPayPlatCreateOrder(payOrderReqVO, tradeOrderPayDO)) {
            //3.调用支付平台，其结果不用于更新订单状态，需要通过支付查询或者异步通知变更订单状态
            Map result = useBcPayPlatCreatePayOrder(payOrderReqVO, tradeOrderPayDO);
            payOrderRespVO.setPayPlatResult(result);
            if (result != null) {
                tradeOrderPayDO.setPayParams(JsonUtils.toJsonString(result));
            }
            tradeOrderRepositoryService.updatePayOrderPayParams(tradeOrderPayDO);
        } else {
            //4.其他支付方式
            String tradeId = useOtherPayType(payOrderReqVO, tradeOrderPayDO);
            tradeOrderPayDO.setPaymentNo(tradeId);
            //4.1支付成功
            TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(payOrderReqVO.getOrderId());
            updateBcOrderPaid(tradeOrderDO, tradeOrderPayDO);
        }
        return CommonResult.success(payOrderRespVO);
    }

    private CommonResult<?> afterPaySuccessWithHeldLock(TradeOrderPayDO tradeOrderPayDO) {
        //更新支付单状态
        updatePayOrderSuccess(tradeOrderPayDO);
        //处理其他订单支付
        CommonResult<?> commonResult = handleOtherPayOrder(tradeOrderPayDO);
        if (commonResult != null) {
            return commonResult;
        }
        //验证订单状态
        Long orderId = tradeOrderPayDO.getOrderId();
        TradeOrderDO tradeOrderDO = tradeOrderRepositoryService.getById(orderId);
        //订单变更为已支付
        updateOrderPaid(tradeOrderDO, tradeOrderPayDO);
        //向供应商出票
        CommonResult<?> result = tradeSupplierService.payOrder(tradeOrderDO);
        if (result.isError()) {
            tradeSupplierCallbackService.afterAnyOrderPayFail(tradeOrderDO);
            return result;
        }
        tradeSupplierCallbackService.afterAllOrderPay(tradeOrderDO);
        return CommonResult.success(null);
    }

    private void afterPaySuccess(TradeOrderPayDO tradeOrderPayDO) {

        Long orderId = tradeOrderPayDO.getOrderId();
        String lockKey = String.format(UPDATE_ORDER_LOCK, orderId);
        RLock lock = redissonClient.getLock(lockKey);
        try {
            if (lock.tryLock(60, 90, TimeUnit.SECONDS)) {
                afterPaySuccessWithHeldLock(tradeOrderPayDO);
            } else {
                CommonResult.error(GET_LOCK_EXCEPTION);
            }
        } catch (ServiceException e) {
            ExceptionUtils.log(log, "订单更新异常orderId:" + orderId, e);
            CommonResult.error(e);
        } catch (Exception e) {
            log.error("订单更新异常orderId:{}", orderId, e);
            CommonResult.error(UNKNOWN_EXCEPTION);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    //    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_PAY)
    public void updateOrderPaid(TradeOrderDO tradeOrderDO, TradeOrderPayDO tradeOrderPayDO) {
        Integer orderStatus = tradeOrderDO.getOrderStatus();
        tradeOrderDO.setOrderStatus(TradeOrderStatusEnum.PAID.getStatus());
        //支付时间暂时用当前
        tradeOrderDO.setPaymentDate(LocalDateTime.now());
        tradeOrderDO.setPayStatus(PaymentStatusEnum.PAID.getStatus());
        BigDecimal realPayAmount = tradeOrderDO.getRealPayAmount() == null ? BigDecimal.ZERO : tradeOrderDO.getRealPayAmount();
        tradeOrderDO.setRealPayAmount(realPayAmount.add(tradeOrderPayDO.getPayAmount()));
        tradeOrderRepositoryService.updateOrderAfterAllPay(tradeOrderDO);
        //保存订单日志
        try {
            Long userId = getLoginUserId();
            TradeOrderLogDO tradeOrderLogDO = new TradeOrderLogDO();
            tradeOrderLogDO.setOrderId(tradeOrderDO.getId());
            tradeOrderLogDO.setUserId(userId);
            tradeOrderLogDO.setUserType(2);
            tradeOrderLogDO.setTenantId(1L);
            tradeOrderLogDO.setCreateTime(LocalDateTime.now());
            tradeOrderLogDO.setDeleted(false);
            tradeOrderLogDO.setId(IdWorker.getId(tradeOrderLogDO));
            tradeOrderLogDO.setOperateType(TradeOrderOperateTypeEnum.ORDER_PAY.getType());
            tradeOrderLogDO.setBeforeStatus(orderStatus);
            tradeOrderLogDO.setAfterStatus(tradeOrderDO.getOrderStatus());
            tradeOrderLogDO.setContent(TradeOrderOperateTypeEnum.ORDER_PAY.getContent().replaceAll("{payType}", PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()).getName()).replaceAll("{payAmount}", tradeOrderPayDO.getPayAmount().toString()));
            tradeOrderLogMapper.insert(tradeOrderLogDO);
        } catch (Exception e) {
            log.error("保存订单日志异常orderId:{}", tradeOrderDO.getId(), e);
        }
//        TradeOrderLogUtils.setOrderInfo(tradeOrderDO.getId(), orderStatus, tradeOrderDO.getOrderStatus(), MapUtil.<String, Object>builder().put("payType", PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()).getName()).put("payAmount", tradeOrderPayDO.getPayAmount()).build());
    }

    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_DEPOSI_PAY)
    public void updateDeposiOrderPaid(TradeOrderDO tradeOrderDO, TradeOrderPayDO tradeOrderPayDO) {
        Integer orderStatus = tradeOrderDO.getOrderStatus();
        BigDecimal realPayAmount = (tradeOrderDO.getRealPayAmount() == null ? BigDecimal.ZERO : tradeOrderDO.getRealPayAmount()).add(tradeOrderPayDO.getPayAmount());
        tradeOrderMapper.update(new LambdaUpdateWrapper<TradeOrderDO>()
                .eq(TradeOrderDO::getId, tradeOrderDO.getId())
                .set(TradeOrderDO::getRealPayAmount, realPayAmount)
                .set(TradeOrderDO::getOrderStatus, orderStatus)
                .set(TradeOrderDO::getDeposiStatus, 2)
                .set(TradeOrderDO::getDeposiPayTime, LocalDateTime.now()));
        //保存订单日志
        TradeOrderLogUtils.setOrderInfo(tradeOrderDO.getId(), orderStatus, tradeOrderDO.getOrderStatus(), MapUtil.<String, Object>builder().put("payType", PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()).getName()).put("payAmount", tradeOrderPayDO.getPayAmount()).build());
    }

    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_BC_PAY)
    public void updateBcOrderPaid(TradeOrderDO tradeOrderDO, TradeOrderPayDO tradeOrderPayDO) {
        Integer orderStatus = tradeOrderDO.getOrderStatus();
        BigDecimal realPayAmount = (tradeOrderDO.getRealPayAmount() == null ? BigDecimal.ZERO : tradeOrderDO.getRealPayAmount()).add(tradeOrderPayDO.getPayAmount());
        tradeOrderMapper.update(new LambdaUpdateWrapper<TradeOrderDO>()
                .eq(TradeOrderDO::getId, tradeOrderDO.getId())
                .set(TradeOrderDO::getRealPayAmount, realPayAmount)
                .set(TradeOrderDO::getOrderStatus, orderStatus)
                .set(TradeOrderDO::getIsSupplementary, 2)
                .set(TradeOrderDO::getUpdateTime, LocalDateTime.now()));
        //保存订单日志
        TradeOrderLogUtils.setOrderInfo(tradeOrderDO.getId(), orderStatus, tradeOrderDO.getOrderStatus(), MapUtil.<String, Object>builder().put("payType", PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()).getName()).put("payAmount", tradeOrderPayDO.getPayAmount()).build());
    }

    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_PAY)
    public void updateOrderPaying(TradeOrderDO tradeOrderDO, TradeOrderPayDO tradeOrderPayDO) {
        Integer orderStatus = tradeOrderDO.getOrderStatus();
        if (ObjectUtil.equal(tradeOrderDO.getOrderStatus(), TradeOrderStatusEnum.UNPAID.getStatus())) {
            tradeOrderDO.setOrderStatus(TradeOrderStatusEnum.PAYING.getStatus());
            tradeOrderRepositoryService.updateOrderStatus(tradeOrderDO);
        }
        //保存订单日志
        TradeOrderLogUtils.setOrderInfo(tradeOrderDO.getId(), orderStatus, tradeOrderDO.getOrderStatus(), MapUtil.<String, Object>builder().put("payType", PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()).getName()).put("payAmount", tradeOrderPayDO.getPayAmount()).build());
    }

    private void validate(TradeOrderDO tradeOrder, PayOrderReqVO payOrderReqVO) {

        Asserts.isTrue(ObjectUtils.equalsAny(tradeOrder.getOrderStatus(), TradeOrderStatusEnum.UNPAID.getStatus(), TradeOrderStatusEnum.YD.getStatus(), TradeOrderStatusEnum.PAYING.getStatus()), "当前状态无法支付{}", tradeOrder.getOrderStatus());
        if (ObjectUtil.equal(tradeOrder.getSellMethod(), SellMethodEnum.OTC_MOVE_ORDER.getType()) && ObjectUtil.notEqual(tradeOrder.getIsChangeOrder(), ORDER_CHANGE_TYPE_NEW)) {
            //如果旅行社搬单,必须一次性支付
//            Asserts.isTrue(tradeOrder.getPayAmount().compareTo(payOrderReqVO.getPayAmount()) == 0, "支付金额需等于订单支付金额");
            //支付方式不能为现金，支付金额不能为0
            Asserts.isTrue(ObjectUtil.notEqual(payOrderReqVO.getPayType(), PayTypeEnum.CASH.getType()), "支付方式不能为现金");
        }
        if (ObjectUtils.equalsAny(tradeOrder.getSellMethod(), SellMethodEnum.MINI_APP.getType())) {
            if (ObjectUtil.equal(payOrderReqVO.getPayType(), PayTypeEnum.OTHER.getType())) {
                Asserts.isTrue(payOrderReqVO.getPayAmount().compareTo(BigDecimal.ZERO) == 0, "当前渠道支付方式错误");
            }
        }
        //平台订单，验证当前登录分销商是否有该订单权限
        if (ObjectUtils.equalsAny(tradeOrder.getSellMethod(), SellMethodEnum.OTC_MOVE_ORDER.getType(), SellMethodEnum.OTA_SYSTEM.getType())) {
            DistributorRespDTO distributorRespDTO = agencyAuthUtils.getLoginUserDistributorData();
            if (distributorRespDTO != null) {
                Asserts.isTrue(ObjectUtil.equal(distributorRespDTO.getId().toString(), tradeOrder.getSourceId()), "当前账号无该数据权限");
            }
        }
    }

    /**
     * 需要支付平台创建订单吗？
     */
    private boolean needPayPlatCreateOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO) {
        boolean flag = ObjectUtils.equalsAny(payOrderReqVO.getPayType(), PayTypeEnum.WEIXIN_PAY.getType(), PayTypeEnum.ALI_PAY.getType(), PayTypeEnum.UNION_PAY.getType(), PayTypeEnum.BANK_CARD.getType());
        if (flag && (payOrderReqVO.getPayAmount().compareTo(BigDecimal.ZERO) == 0)) {
            throw exception0(PAY_TYPE_NOT_SUPPORT_ZERO.getCode(), PAY_TYPE_NOT_SUPPORT_ZERO.getMsg());
        }
        return flag;
    }

    private TradeOrderPayDO buildOrderPay(TradeOrderDO tradeOrder, PayOrderReqVO payOrderReqVO) {
        TradeOrderPayDO tradeOrderPayDO = new TradeOrderPayDO();
        tradeOrderPayDO.setId(IdWorker.getId());
        tradeOrderPayDO.setOrderId(tradeOrder.getId());
        tradeOrderPayDO.setOrderNo(tradeOrder.getOrderNo());
        tradeOrderPayDO.setPayStatus(PaymentStatusEnum.INIT.getStatus());
        tradeOrderPayDO.setSellMethod(tradeOrder.getSellMethod());
        tradeOrderPayDO.setPayAmount(payOrderReqVO.getPayAmount());
        tradeOrderPayDO.setPaymentType(payOrderReqVO.getPayType());
        tradeOrderPayDO.setRefundAmount(BigDecimal.ZERO);
        tradeOrderPayDO.setOrderType(PAY_ORDER_TYPE_TRADE);
        return tradeOrderPayDO;
    }

    private void updatePayOrderSuccess(TradeOrderPayDO tradeOrderPayDO) {
        tradeOrderPayDO.setPayStatus(PaymentStatusEnum.PAID.getStatus());
        if (tradeOrderPayDO.getPaymentDate() == null) {
            tradeOrderPayDO.setPaymentDate(LocalDateTime.now());
        }
        tradeOrderRepositoryService.updatePayOrderStatus(tradeOrderPayDO);
    }

    private String useOtherPayType(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO) {
        if (ObjectUtils.equalsAny(payOrderReqVO.getPayType(), PayTypeEnum.CASH.getType(), PayTypeEnum.CORPORATE_TRANSFER_PAY.getType(), PayTypeEnum.TONG_LIAN_SCAN_PAY.getType(), PayTypeEnum.OTHER.getType()) || payOrderReqVO.getPayAmount().compareTo(BigDecimal.ZERO) == 0) {
            return "0";
        }
        if (payOrderReqVO.getPayType() == 5) {
            //预付款
            PayTypeEnum payTypeEnum = PayTypeEnum.valueOf(5);
            PayTypeService payTypeService = payTypeServiceMap.get(payTypeEnum.getServiceName());
            Asserts.isTrue(payTypeService != null, "当前支付方式未实现{},{}", payTypeEnum.getServiceName(), payOrderReqVO.getPayType());
            if (payTypeService != null) {
                return payTypeService.deduct(tradeOrderPayDO, payOrderReqVO).toString();
            }
        } else if (payOrderReqVO.getPayType() == 6) {
            //授信
            PayTypeEnum payTypeEnum = PayTypeEnum.valueOf(6);
            PayTypeService payTypeService = payTypeServiceMap.get(payTypeEnum.getServiceName());
            Asserts.isTrue(payTypeService != null, "当前支付方式未实现{},{}", payTypeEnum.getServiceName(), payOrderReqVO.getPayType());
            if (payTypeService != null) {
                return payTypeService.deduct(tradeOrderPayDO, payOrderReqVO).toString();
            }
        } else {
            //qt
            PayTypeEnum payTypeEnum = PayTypeEnum.valueOf(payOrderReqVO.getPayType());
            PayTypeService payTypeService = payTypeServiceMap.get(payTypeEnum.getServiceName());
            Asserts.isTrue(payTypeService != null, "当前支付方式未实现{},{}", payTypeEnum.getServiceName(), payOrderReqVO.getPayType());
            if (payTypeService != null) {
                return payTypeService.deduct(tradeOrderPayDO, payOrderReqVO).toString();
            }
        }
        return "";
    }

    private Map usePayPlatCreatePayOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO) {
        Asserts.isTrue(payOrderReqVO.getPayParams() != null, "支付参数不能为空");
        //获取当前租户配置的支付平台商户号
        String mchId;
        if (PAY_ORDER_TYPE_OTHER == tradeOrderPayDO.getOrderType()) {
            //如果是其他支付单，获取平台配置
            mchId = configApi.getPlatformConfigValueByKey("payPlatMchId");
        } else {
            //获取当前租户配置的支付平台商户号
            mchId = configApi.getConfigValueByKey("payPlatMchId");
        }
        Asserts.isTrue(StrUtil.isNotBlank(mchId), "当前租户未配置商户号");
        TradeMchInfoDO tradeMchInfoDO = tradeOrderRepositoryService.getByMchId(mchId);
        Asserts.isTrue(tradeMchInfoDO != null, "未配置商户号信息{}", tradeMchInfoDO);
        //根据支付方式获取channelId
        String name = tradeOrderPayDO.getOrderType() == PAY_ORDER_TYPE_TRADE ? SellMethodEnum.valueOf(tradeOrderPayDO.getSellMethod()).name() : PaySourceEnum.valueOf(tradeOrderPayDO.getSellMethod()).name();
        String channelId = getChannelIdByPayType(tradeOrderPayDO.getOrderType(), name, PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()), payOrderReqVO.getPayExtraType());
        if (tradeMchInfoDO != null) {
            tradeOrderPayDO.setMerchantNo(tradeMchInfoDO.getMchId());
        }
        tradeOrderPayDO.setChannelId(channelId);
        tradeOrderPayDO.setOpenId(payOrderReqVO.getOpenId());
        //补充支付参数
        if (tradeOrderPayDO.getOrderType() == PAY_ORDER_TYPE_TRADE) {
            TradeDetailDO tradeDetailDO = tradeOrderRepositoryService.getOrderAnyDetail(tradeOrderPayDO.getOrderId());
            PayOrderReqVO.PayParams payParams = payOrderReqVO.getPayParams();
            payParams.setParam(tradeDetailDO.getProductName());
            payParams.setSubject(payOrderReqVO.getAccountName());
            payParams.setBody(tradeDetailDO.getProductName());
            payParams.setProductId(tradeDetailDO.getProductId().toString());
        }

        JSONObject result = payPlatService.createPayOrder(payOrderReqVO, tradeOrderPayDO, tradeMchInfoDO);
        Asserts.isTrue(StrUtil.equals(SUCCESS, MapUtils.getString(result, "retCode")), "调用支付平台失败");
        //保存支付平台支付单号
        String payOrderId = MapUtil.getStr(result, "payOrderId");
        if (StrUtil.isNotBlank(payOrderId)) {
            tradeOrderPayDO.setPaymentNo(payOrderId);
        }
        if (payOrderReqVO.getPayParams() != null) {
            tradeOrderPayDO.setReqParams(JsonUtils.toJsonString(payOrderReqVO.getPayParams()));
        }

        return result;
    }

    private Map useDeposiPayPlatCreatePayOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO) {
        Asserts.isTrue(payOrderReqVO.getPayParams() != null, "支付参数不能为空");
        //获取当前租户配置的支付平台商户号
        String mchId;
        if (PAY_ORDER_TYPE_OTHER == tradeOrderPayDO.getOrderType()) {
            //如果是其他支付单，获取平台配置
            mchId = configApi.getPlatformConfigValueByKey("payPlatMchId");
        } else {
            //获取当前租户配置的支付平台商户号
            mchId = configApi.getConfigValueByKey("payPlatMchId");
        }
        Asserts.isTrue(StrUtil.isNotBlank(mchId), "当前租户未配置商户号");
        TradeMchInfoDO tradeMchInfoDO = tradeOrderRepositoryService.getByMchId(mchId);
        Asserts.isTrue(tradeMchInfoDO != null, "未配置商户号信息{}", tradeMchInfoDO);
        //根据支付方式获取channelId
        String name = SellMethodEnum.valueOf(tradeOrderPayDO.getSellMethod()).name();
        String channelId = getChannelIdByPayType(tradeOrderPayDO.getOrderType(), name, PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()), payOrderReqVO.getPayExtraType());
        if (tradeMchInfoDO != null) {
            tradeOrderPayDO.setMerchantNo(tradeMchInfoDO.getMchId());
        }
        tradeOrderPayDO.setChannelId(channelId);
        tradeOrderPayDO.setOpenId(payOrderReqVO.getOpenId());
        //补充支付参数
        if (tradeOrderPayDO.getOrderType() == PAY_ORDER_TYPE_DEPOSI) {
            TradeDetailDO tradeDetailDO = tradeOrderRepositoryService.getOrderAnyDetail(tradeOrderPayDO.getOrderId());
            PayOrderReqVO.PayParams payParams = payOrderReqVO.getPayParams();
            payParams.setParam(tradeDetailDO.getProductName());
            payParams.setSubject(payOrderReqVO.getAccountName());
            payParams.setBody(tradeDetailDO.getProductName());
            payParams.setProductId(tradeDetailDO.getProductId().toString());
        }

        JSONObject result = payPlatService.createDeposiPayOrder(payOrderReqVO, tradeOrderPayDO, tradeMchInfoDO);
        Asserts.isTrue(StrUtil.equals(SUCCESS, MapUtils.getString(result, "retCode")), "定金支付调用支付平台失败");
        //保存支付平台支付单号
        String payOrderId = MapUtil.getStr(result, "payOrderId");
        if (StrUtil.isNotBlank(payOrderId)) {
            tradeOrderPayDO.setPaymentNo(payOrderId);
        }
        if (payOrderReqVO.getPayParams() != null) {
            tradeOrderPayDO.setReqParams(JsonUtils.toJsonString(payOrderReqVO.getPayParams()));
        }

        return result;
    }

    private Map useBcPayPlatCreatePayOrder(PayOrderReqVO payOrderReqVO, TradeOrderPayDO tradeOrderPayDO) {
        Asserts.isTrue(payOrderReqVO.getPayParams() != null, "支付参数不能为空");
        //获取当前租户配置的支付平台商户号
        String mchId;
        if (PAY_ORDER_TYPE_OTHER == tradeOrderPayDO.getOrderType()) {
            //如果是其他支付单，获取平台配置
            mchId = configApi.getPlatformConfigValueByKey("payPlatMchId");
        } else {
            //获取当前租户配置的支付平台商户号
            mchId = configApi.getConfigValueByKey("payPlatMchId");
        }
        Asserts.isTrue(StrUtil.isNotBlank(mchId), "当前租户未配置商户号");
        TradeMchInfoDO tradeMchInfoDO = tradeOrderRepositoryService.getByMchId(mchId);
        Asserts.isTrue(tradeMchInfoDO != null, "未配置商户号信息{}", tradeMchInfoDO);
        //根据支付方式获取channelId
        String name = SellMethodEnum.valueOf(tradeOrderPayDO.getSellMethod()).name();
        String channelId = getChannelIdByPayType(tradeOrderPayDO.getOrderType(), name, PayTypeEnum.valueOf(tradeOrderPayDO.getPaymentType()), payOrderReqVO.getPayExtraType());
        if (tradeMchInfoDO != null) {
            tradeOrderPayDO.setMerchantNo(tradeMchInfoDO.getMchId());
        }
        tradeOrderPayDO.setChannelId(channelId);
        tradeOrderPayDO.setOpenId(payOrderReqVO.getOpenId());
        //补充支付参数
        if (tradeOrderPayDO.getOrderType() == PAY_ORDER_TYPE_BC) {
            TradeDetailDO tradeDetailDO = tradeOrderRepositoryService.getOrderAnyDetail(tradeOrderPayDO.getOrderId());
            PayOrderReqVO.PayParams payParams = payOrderReqVO.getPayParams();
            payParams.setParam(tradeDetailDO.getProductName());
            payParams.setSubject(payOrderReqVO.getAccountName());
            payParams.setBody(tradeDetailDO.getProductName());
            payParams.setProductId(tradeDetailDO.getProductId().toString());
        }

        JSONObject result = payPlatService.createBcPayOrder(payOrderReqVO, tradeOrderPayDO, tradeMchInfoDO);
        Asserts.isTrue(StrUtil.equals(SUCCESS, MapUtils.getString(result, "retCode")), "定金支付调用支付平台失败");
        //保存支付平台支付单号
        String payOrderId = MapUtil.getStr(result, "payOrderId");
        if (StrUtil.isNotBlank(payOrderId)) {
            tradeOrderPayDO.setPaymentNo(payOrderId);
        }
        if (payOrderReqVO.getPayParams() != null) {
            tradeOrderPayDO.setReqParams(JsonUtils.toJsonString(payOrderReqVO.getPayParams()));
        }

        return result;
    }

    private String getChannelIdByPayType(int orderType, String name, PayTypeEnum payType, Integer payExtraType) {
        String key = name + "_" + payType.name();
        if (payExtraType != null) {
            key += "_" + payExtraType;
        }
        String channelId = getPayChannelId(orderType, key);
        Asserts.isTrue(StrUtil.isNotBlank(channelId), "当前支付方式未配置channelId,{}", key);
        return channelId;
    }


    private CommonResult<?> handleOtherPayOrder(TradeOrderPayDO tradeOrderPayDO) {
        if (tradeOrderPayDO.getOrderType() != PAY_ORDER_TYPE_OTHER) {
            return null;
        }
        //分销商在线充值
        if (ObjectUtil.equal(tradeOrderPayDO.getSellMethod(), PaySourceEnum.DISTRIBUTOR_RECHARGE_ORDER.getType())) {
            DistributorSelfRechargeReqDTO payNotifyReqDTO = new DistributorSelfRechargeReqDTO();
            payNotifyReqDTO.setPayOrderId(String.valueOf(tradeOrderPayDO.getId()));
            payNotifyReqDTO.setOrderId(tradeOrderPayDO.getOrderId());
            payNotifyReqDTO.setPayStatus(1);
            otaDistributorApi.distributorSelfRecharge(payNotifyReqDTO).getCheckedData();
        }
        //授信账单还款
        if (ObjectUtil.equal(tradeOrderPayDO.getSellMethod(), PaySourceEnum.CREDIT_BILL_REPAYMENT.getType())) {
            BillPayReqDTO billPayReqDTO = new BillPayReqDTO();
            billPayReqDTO.setPayOrderId(tradeOrderPayDO.getId());
            billPayReqDTO.setOrderId(tradeOrderPayDO.getOrderId());
            billPayReqDTO.setPayStatus(1);
            billPayReqDTO.setPayType(tradeOrderPayDO.getPaymentType());
            billPayReqDTO.setPayUserId(Long.parseLong(tradeOrderPayDO.getCreator()));
            List<DistributorRechargeReqDTO> commonResult = billService.billPayNotice(billPayReqDTO);
            if (commonResult != null) {
                //需自动退款
                log.error("授信账单还款订单，自动退款,支付单{},金额{}", tradeOrderPayDO.getId(), tradeOrderPayDO.getPayAmount());

                tradeRefundService.autoRefundByPayOrder(tradeOrderPayDO.getId());
            }
            return CommonResult.success(commonResult);
        }
        return CommonResult.success(null);
    }

    /**
     * 检查外部的订单此时是否可以支付
     */
    private void canPayByCheckOuterOrderId(TradeOrderPayDO tradeOrderPayDO, PayOrderReqVO payOrderReqVO) {
        if (tradeOrderPayDO.getOrderType() != PAY_ORDER_TYPE_OTHER) {
            return;
        }

        if (ObjectUtil.equal(tradeOrderPayDO.getSellMethod(), PaySourceEnum.CREDIT_BILL_REPAYMENT.getType())) {
            Boolean flag = billService.billPayVerification(tradeOrderPayDO.getOrderId());
            Asserts.isTrue(flag, "当前订单已支付，不能重复支付");
        }

        if (ObjectUtil.equal(tradeOrderPayDO.getSellMethod(), PaySourceEnum.GUIDE_REFUND_PLAT_CHARGEBACK.getType())) {
            //支付方式只能是预付款
            Asserts.isTrue(ObjectUtils.equalsAny(tradeOrderPayDO.getPaymentType(), PayTypeEnum.ADVANCE_PAYMENT.getType()), "当前订单不支持此支付方式");
        }

        //验证当前登录用户是否有此分销商权限，防止数据越权
        if (ObjectUtils.equalsAny(tradeOrderPayDO.getSellMethod(), PaySourceEnum.CREDIT_BILL_REPAYMENT.getType(), PaySourceEnum.STOCK_DIRECT_ORDER.getType())) {
            DistributorRespDTO distributorRespDTO = agencyAuthUtils.getLoginUserDistributorData();
            if (distributorRespDTO != null) {
                Asserts.isTrue(ObjectUtil.equal(distributorRespDTO.getId().toString(), payOrderReqVO.getAccountId()), "当前账号无该数据权限");
            }
        }
    }

    public String getPayChannelId(int orderType, String configKey) {
        String channelId;
        if (orderType == PAY_ORDER_TYPE_OTHER) {
            channelId = configApi.getPlatformConfigValueByKey(configKey);
        } else {
            channelId = configApi.getConfigValueByKey(configKey);
        }
        return channelId;
    }

    @Override
    public CommonResult<?> queryOrderContract(Long payOrderId) {
        List<Map<String, Object>> mapList = tradeOrderRepositoryService.selectContractByOrderId(payOrderId);
        if (mapList != null && !mapList.isEmpty()) {
            Map<String, Object> contractMap = mapList.get(0);
            String signingUrl = MapUtil.getStr(contractMap, "signing_url", "");
            String viewUrl = MapUtil.getStr(contractMap, "view_url", "");
            Date paymentDate = MapUtil.getDate(contractMap, "paymentDate");
            Date now = DateUtil.date();

            //状态 0:签订中 1:已签订 2:作废中 3:已作废
            int status = MapUtil.getInt(contractMap, "status", 0);
            if (status == 1) {
                return CommonResult.error(400, "当前订单合同已签订" + viewUrl);
            } else if (status == 0) {
                if (StringUtils.isEmpty(signingUrl) && paymentDate != null && DateUtil.between(paymentDate, now, DateUnit.MINUTE) <= 10) {
                    Map<String, Object> resMap = new HashMap<>();
                    resMap.put("isSigning", false);
                    return CommonResult.success(resMap);
                } else if (StringUtils.isEmpty(signingUrl) && paymentDate != null && DateUtil.between(paymentDate, now, DateUnit.MINUTE) > 10) {
                    return CommonResult.error(401, "合同不存在");
                }
                Map<String, Object> resMap = new HashMap<>();
                resMap.put("signingUrl", signingUrl);
                resMap.put("status", status);
                resMap.put("isSigning", true);
                return CommonResult.success(resMap);
            } else {
                return CommonResult.error(402, "当前订单合同已作废");
            }
        }
        return CommonResult.error(500, "合同不存在");
    }

    public static void main(String[] args) {
        System.out.println(DateUtil.parseLocalDateTime("20260304", DatePattern.PURE_DATETIME_PATTERN));
    }

}
