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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;

import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.tenant.core.aop.TenantIgnore;
import com.yc.ship.framework.tenant.core.context.TenantContextHolder;
import com.yc.ship.framework.tenant.core.util.TenantUtils;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.product.api.ProductApi;
import com.yc.ship.module.product.api.dto.ProductBaseRespDTO;
import com.yc.ship.module.product.api.dto.ProductCheckRuleRespDTO;
import com.yc.ship.module.resource.enums.UseStatusEnum;
import com.yc.ship.module.product.api.dto.CheckChannelRespDTO;
import com.yc.ship.module.trade.controller.admin.order.vo.check.TradeCheckReqVO;
import com.yc.ship.module.trade.controller.admin.order.vo.check.TradeCheckRespVO;
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.*;
import com.yc.ship.module.trade.dal.mysql.supplier.TradeSupplierOrderMapper;
import com.yc.ship.module.trade.enums.*;
import com.yc.ship.module.trade.framework.annotation.TradeOrderLog;
import com.yc.ship.module.trade.framework.common.TradeOrderLogUtils;
import com.yc.ship.module.trade.framework.mq.TradePublishUtils;
import com.yc.ship.module.trade.service.order.TradeCheckHandleService;
import com.yc.ship.module.trade.service.order.TradeOrderBizService;
import com.yc.ship.module.trade.service.order.TradeOrderRepositoryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

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.exception;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.*;
import static com.yc.ship.module.trade.service.order.TradeOrderService.UPDATE_ORDER_LOCK;


/**
 * 订单核销服务
 *
 * @author JuneQI
 * @date 2025/8/16 17:39
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class TradeCheckHandleServiceImpl implements TradeCheckHandleService {
    private final TradeSupplierOrderMapper tradeSupplierOrderMapper;
    /**
     * 待确认规格 (%s -> 设备id)
     */
    String TO_CONFIRM_SPEC = "gateCheck:toConfirm:%s";

    private final ConfigApi configApi;
    private final ProductApi productApi;
    private final RedissonClient redissonClient;
    private final TradePublishUtils tradePublishUtils;
    private final TradeOrderMapper tradeOrderMapper;
    private final TradeDetailMapper tradeDetailMapper;
    private final TradeDetailBaseMapper tradeDetailBaseMapper;
    private final TradeCheckMapper tradeCheckMapper;
    private final TradeCheckDetailMapper tradeCheckDetailMapper;
    private final TradeOrderRepositoryService tradeOrderRepositoryService;
    private final TradeOrderBizService tradeOrderBizService;

    /**
     * 订单核销校验
     *
     * @param orderDO 订单
     */
    private void checkOrderVerify(TradeOrderDO orderDO) {
        if (orderDO == null) {
            throw exception(ORDER_NOT_EXIST);
        }
    }


    /**
     * 产品(门票)核销校验
     *
     * @param tradeDetail     产品
     * @param checkReqVO      记录
     * @param tradeDetailBase 子票
     */
    private void checkVoucherVerify(TradeDetailDO tradeDetail, TradeCheckReqVO checkReqVO, TradeDetailBaseDO tradeDetailBase) {

        // 凭证码状态校验
        Assert.isTrue(VoucherStatusEnum.canCheck(tradeDetail.getVoucherStatus()), () -> exception(VOUCHER_STATUS_ERROR));

        // 门票使用日期校验
        String useDateStr = LocalDateTimeUtil.format(tradeDetail.getUseDate(), "yyyy-MM-dd");
        Assert.isTrue(Objects.equals(useDateStr, DateUtil.today()), () -> exception(TRAVEL_DATE_ERROR));

        // 门票使用日期范围校验
        boolean inDateRange = tradeDetail.getValidityStartDate().isBefore(LocalDateTime.now())
                && tradeDetail.getValidityEndDate().isAfter(LocalDateTime.now());
        Assert.isTrue(inDateRange, () -> exception(USE_DATE_RANGE_ERROR));

        ProductCheckRuleRespDTO productCheckRule = tradeDetailMapper.getProductCheckRule(tradeDetail.getProductId());
        if (!Objects.isNull(productCheckRule.getEnterVerifyType())) {
            // 取票后可用校验
            if (Objects.equals(productCheckRule.getCheckRule(), 0)) {
                Assert.isTrue((VoucherStatusEnum.hasTook(tradeDetail.getVoucherStatus())),
                        () -> exception(BEFORE_TOOK_STATUS_ERROR));
            }
        }


        // 子票核销校验
        if (tradeDetailBase != null) {
            TradeCheckRespVO respVO = checkVoucherBaseVerify(tradeDetailBase, checkReqVO);
            Assert.isTrue(respVO.getIsSuccess() == 1, () -> exception(30_111,respVO.getMsg()));
        } else {
            List<TradeDetailBaseDO> tradeDetailBaseList = tradeDetailBaseMapper.selectProductBaseList(tradeDetail.getId(), checkReqVO.getChannelId());
            Assert.isTrue(!tradeDetailBaseList.isEmpty(), () -> exception(NO_SUB_TICKET_ERROR));
            List<TradeCheckRespVO> list = new ArrayList<>();

            for (TradeDetailBaseDO item : tradeDetailBaseList) {
                list.add(checkVoucherBaseVerify(item, checkReqVO));
            }
            long count = list.stream().filter(item -> item.getIsSuccess() == 1).count();
            Assert.isTrue(count > 0, () -> exception(NO_SUB_TICKET_CHECK_SUCCESS));
        }
    }

    /**
     * 基础产品(子票)核销校验
     *
     * @param tradeDetailBase 产品
     * @param checkReqVO      参数
     */
    private TradeCheckRespVO checkVoucherBaseVerify(TradeDetailBaseDO tradeDetailBase, TradeCheckReqVO checkReqVO) {
        TradeCheckRespVO checkResult = TradeCheckRespVO.builder()
                .targetType(CheckTargetTypeEnum.Voucher_Base.getType())
                .targetId(tradeDetailBase.getId())
                .targetNo(tradeDetailBase.getDetailId().toString())
                .isSuccess(0).isPreSuccess(0)
                .build();
        if (!VoucherStatusEnum.canCheckForSub(tradeDetailBase.getUseStatus())) {
            checkResult.setMsg(TRADE_DETAIL_BASE_STATUS_ERROR.getMsg());
            return checkResult;
        }
        CommonResult<ProductBaseRespDTO> productBase = productApi.getProductBaseById(tradeDetailBase.getProductBaseId());
        // 基础产品检票次数校验
        List<TradeCheckDetailDO> tradeDetailBaseList = tradeCheckDetailMapper.selectList(new LambdaQueryWrapper<TradeCheckDetailDO>()
                .eq(TradeCheckDetailDO::getDetailBaseId, tradeDetailBase.getId())
                .eq(TradeCheckDetailDO::getDetailId, tradeDetailBase.getDetailId())
                .eq(TradeCheckDetailDO::getDeleted, 0)
        );
        if (productBase.getData() != null && productBase.getData().getCheckTimes() <= tradeDetailBaseList.size()) {
            checkResult.setMsg(TRADE_DETAIL_BASE_COUNT_ERROR.getMsg());
            return checkResult;
        }
        if (CheckTypeEnum.isMachine(checkReqVO.getType()) || !Objects.isNull(checkReqVO.getChannelId())) {
            // 验证基础产品通道是否与设备通道一致
            Optional<CheckChannelRespDTO> first = productBase.getData().getCheckChannelList().stream()
                    .filter(item -> item.getChannelId().equals(checkReqVO.getChannelId())).findFirst();
            if (!first.isPresent()) {
                checkResult.setMsg(CHANNEL_ERROR.getMsg());
                return checkResult;
            }
        }
        // 基础产品点位校验
        if (!Objects.isNull(checkReqVO.getPointId()) && !Objects.isNull(tradeDetailBase.getStartPoint())) {
            if (checkReqVO.getPointId().equals(tradeDetailBase.getStartPoint())) {
                checkResult.setMsg(POINT_NO_MATCHED.getMsg());
                return checkResult;
            }
        }

        checkResult.setIsSuccess(1);
        checkResult.setMsg("子票核销成功");
        return checkResult;
    }

    /**
     * 票号核销
     *
     * @param checkCode  票号
     * @param checkReqVO 参数
     * @param detailDO   门票
     */
    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_CHECK)
    public TradeCheckRespVO checkVoucherHandle(String checkCode, TradeCheckReqVO checkReqVO, TradeDetailDO detailDO) {
        boolean confirm = false;
        Long s1 = System.currentTimeMillis();
        if (CheckTypeEnum.needConfirmCard(checkReqVO.getType()))    {
            String confirmCard = configApi.getPlatformConfigValueByKey("confirm_card");
            if (!Objects.isNull(confirmCard) && Objects.equals(checkReqVO.getType(), CheckTypeEnum.Gate.getType()) && !Objects.equals(checkReqVO.getType(), CheckTypeEnum.Ren.getType())) {
                // 闸机核销 确认卡
                List<String> confirmCardList = Arrays.asList(confirmCard.split(","));
                if (confirmCardList.contains(checkCode)) {
                    RBucket<Object> bucket = redissonClient.getBucket(String.format(TO_CONFIRM_SPEC, checkReqVO.getMachineId()));
                    checkReqVO = JSONUtil.toBean((String) bucket.get(), TradeCheckReqVO.class);
                    bucket.delete();
                    if (checkReqVO != null) {
                        TenantContextHolder.setIgnore(true);
                        detailDO = tradeDetailMapper.getOneByVoucherCodePlat(checkReqVO.getCheckCodes());
                        TenantContextHolder.setIgnore(false);
                        confirm = true;
                    }
                }
            }
        }
        if (detailDO == null) {
            TenantContextHolder.setIgnore(true);
            detailDO = tradeDetailMapper.getOneByVoucherCode(checkCode);
            TenantContextHolder.setIgnore(false);
        }
        if (detailDO == null) {
            throw exception(TRADE_DETAIL_NOT_EXIST);
        }

        TradeCheckRespVO respVO = TradeCheckRespVO.builder()
                .targetType(CheckTargetTypeEnum.Voucher.getType())
                .targetId(detailDO.getId())
                .targetNo(detailDO.getVoucherCode())
                .isSuccess(0).isPreSuccess(0)
                .build();
        try {
            if (checkReqVO != null && checkReqVO.getType() != null && checkReqVO.getType() == 0 && checkReqVO.getCodeType() == 0) {
                throw exception(INVALID_TYPE_DEVICE);
            }
            // 核销操作记录
            Integer statusOld = 7;
            Integer statusNew = 7;
            respVO.setProductName(detailDO.getProductName());
            respVO.setIsYearTicket(false);
            if (UseStatusEnum.ENABLE.getStatus().equals(checkReqVO.getIsPreCheck())) {
                respVO.setIsPreSuccess(1);
                try {
                    String productTag4 = tradeDetailMapper.getProductTag4(detailDO.getProductId());
                    if (StringUtils.isNotBlank(productTag4) && StringUtils.equals("1", productTag4)) {
                        respVO.setIsYearTicket(true);
                        respVO.setType("General");
                    }else if (StringUtils.isNotBlank(productTag4) && StringUtils.equals("2", productTag4)) {
                        respVO.setIsYearTicket(true);
                        respVO.setType("Short");
                    }
                }catch (Exception e){
                    log.error("获取产品标签4失败", e);
                }
                respVO.setMsg("预检成功");
                try {
                    //预检存检票记录
                    // 门票核销记录
                    TradeCheckDO detailLog = BeanUtil.toBean(checkReqVO, TradeCheckDO.class);
                    detailLog.setOrderId(detailDO.getOrderId());
                    detailLog.setDetailId(detailDO.getId());
                    detailLog.setType(CheckTypeEnum.GatePreCheck.getType());
                    detailLog.setOriginalStatus(detailDO.getVoucherStatus());
                    detailLog.setVoucherCode(detailDO.getVoucherCode());
                    detailLog.setOperatorName("闸机预检");
                    tradeCheckMapper.insert(detailLog);
                }catch (Exception e){
                    log.error("预检存检票记录失败", e);
                }

            } else {
                Long s4 = System.currentTimeMillis();
                log.error("{}检票时间4{}",detailDO.getVoucherCode(), s4-s1);
                updateVoucherStatus(detailDO, checkReqVO, null);
                respVO.setIsSuccess(1);
                respVO.setMsg("核销成功");
                // 推送核销结果消息
                if (respVO.getIsSuccess() == 1) {
                    tradePublishUtils.checkVoucherSuccessMsg(detailDO.getId().toString());
                    tradePublishUtils.updateOrderStatusMsg(detailDO.getOrderId()+"");
                }
                Long s5 = System.currentTimeMillis();
                log.error("{}检票时间5:{}",detailDO.getVoucherCode(), s5-s4);
            }
            TradeOrderLogUtils.setOrderInfo(detailDO.getOrderId(), statusOld, statusNew,
                    buildExtMap(respVO, checkReqVO, detailDO.getCheckedDetailBaseNames()));
        } catch (Exception e) {
            e.printStackTrace();
            log.error("核销门票(组合产品)voucherCode:{}: {}", detailDO.getVoucherCode(), e.toString());
            respVO.setMsg(e.getMessage());
        }
        return respVO;
    }

    private Map<String, Object> buildExtMap(TradeCheckRespVO respVO, TradeCheckReqVO checkReqVO, String detailBaseNames) {
        Map<String, Object> extMap = new HashMap<>();
        extMap.put("checkCodeType", CheckCodeTypeEnum.getName(checkReqVO.getCodeType()));
        extMap.put("targetNo", respVO.getTargetNo());
        extMap.put("checkType", CheckTypeEnum.getName(checkReqVO.getType()));
        extMap.put("machineInfo", StrUtil.isNotBlank(checkReqVO.getMachineName())?"在【"+checkReqVO.getMachineName()+"】设备处, ":"");
        String res;
        if(respVO.getIsSuccess() == 1){
            res = "成功";
        }else{
            if(respVO.getIsPreSuccess() == 1){
                res = "预检成功";
            }else{
                res = "失败: " + respVO.getMsg() + "，子票: (" + detailBaseNames + ")";
            }
        }
        extMap.put("checkResult", res);
        return extMap;
    }

    /**
     * 订单号核销
     *
     * @param checkCode  订单号
     * @param checkReqVO 参数
     */
    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_CHECK)
    public List<TradeCheckRespVO> checkOrderHandle(String checkCode, TradeCheckReqVO checkReqVO) {

        TradeOrderDO orderDO = tradeOrderMapper.queryOneByOrderNo(checkCode);
        checkOrderVerify(orderDO);

        List<TradeCheckRespVO> result = new ArrayList<>();
        List<TradeDetailDO> detailDOList = tradeDetailMapper.selectList(TradeDetailDO::getOrderId, orderDO.getId());
        for (TradeDetailDO detailDO : detailDOList) {
            result.add(checkVoucherHandle(null, checkReqVO, detailDO));
        }
        if (UseStatusEnum.DISABLE.getStatus().equals(checkReqVO.getIsPreCheck())) {
            long count = result.stream().filter(item -> item.getIsSuccess() == 1).count();
            int orderStatus = count == result.size() ? TradeOrderStatusEnum.ALL_CHECK.getStatus() : TradeOrderStatusEnum.PART_CHECK.getStatus();
            tradeOrderMapper.updateOrderStatus(orderDO.getId(), orderStatus);
            // 推送核销结果消息
            if (count == result.size()) {
                result.add(TradeCheckRespVO.builder()
                        .targetType(CheckTargetTypeEnum.Order.getType())
                        .targetId(orderDO.getId())
                        .targetNo(orderDO.getOrderNo())
                        .isSuccess(1)
                        .msg("订单核销成功").build());
                Integer statusOld = orderDO.getOrderStatus();
                Integer statusNew = orderStatus;

                Map<String, Object> extMap = new HashMap<>();
                extMap.put("checkCodeType", CheckCodeTypeEnum.getName(checkReqVO.getCodeType()));
                extMap.put("targetNo", orderDO.getOrderNo());
                extMap.put("checkType", CheckTypeEnum.getName(checkReqVO.getType()));
                extMap.put("machineInfo", StrUtil.isNotBlank(checkReqVO.getMachineName())?"在【"+checkReqVO.getMachineName()+"】设备处, ":"后台");
                String res = "成功";
                extMap.put("checkResult", res);
                TradeOrderLogUtils.setOrderInfo(orderDO.getId(), statusOld, statusNew,extMap);
            }
        }
        return result;
    }

    /**
     * 证件号核销
     *
     * @param checkCode  证件号
     * @param checkReqVO 参数
     */
    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_CHECK)
    public List<TradeCheckRespVO> checkCardNoHandle(String checkCode, TradeCheckReqVO checkReqVO) {
        TradeDetailDO detailDO = tradeDetailMapper.getOneByCardNoAndChannelId(checkReqVO.getChannelId(),checkCode);
        TradeCheckRespVO respVO;
        if (detailDO!=null) {
            respVO = checkVoucherHandle(null, checkReqVO, detailDO);
            // 推送核销结果消息
            if (respVO.getIsSuccess() == 1) {
                tradePublishUtils.checkVoucherSuccessMsg(detailDO.getId().toString());
            }
            // 核销操作记录
            Integer statusOld = 7;
            Integer statusNew = 7;
            if (respVO.getIsSuccess() == 1) {
                tradePublishUtils.updateOrderStatusMsg(detailDO.getOrderId()+"");
            }
            TradeOrderLogUtils.setOrderInfo(detailDO.getOrderId(), statusOld, statusNew,
                    buildExtMap(respVO, checkReqVO, detailDO.getCheckedDetailBaseNames()));
        } else {
            respVO = TradeCheckRespVO.builder()
                    .targetType(CheckTargetTypeEnum.Card_No.getType())
                    .targetId(null)
                    .targetNo(checkCode)
                    .isSuccess(0)
                    .msg("未查询到有效票信息")
                    .build();
        }
        return Collections.singletonList(respVO);
    }

    /**
     * 子票核销
     *
     * @param checkCode  子票id
     * @param checkReqVO 参数
     */
    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_CHECK)
    public TradeCheckRespVO checkDetailHandle(String checkCode, TradeCheckReqVO checkReqVO) {
        TradeDetailBaseDO tradeDetailBase = tradeDetailBaseMapper.selectById(checkCode);
        if(tradeDetailBase==null) {
            try {
                tradeDetailBase = tradeDetailBaseMapper.selectDetailBaseBySupplierVoucherCode(checkCode);
            }catch (Exception e){
                throw exception(CHECK_DETAIL_NOT_EXIST);
            }
        }
        if (tradeDetailBase == null) {
            throw exception(CHECK_DETAIL_NOT_EXIST);
        }
        TradeDetailDO tradeDetail = tradeDetailMapper.selectOne(TradeDetailDO::getId, tradeDetailBase.getDetailId());
        if (tradeDetail == null) {
            throw exception(TRADE_DETAIL_NOT_EXIST);
        }
        TradeCheckRespVO respVO = TradeCheckRespVO.builder()
                .targetType(CheckTargetTypeEnum.Voucher_Base.getType())
                .targetId(tradeDetail.getId())
                .targetNo(tradeDetail.getVoucherCode())
                .isSuccess(0).isPreSuccess(0)
                .build();
        String detailKey = String.format(UPDATE_ORDER_LOCK, tradeDetail.getOrderId());
        RLock lock = redissonClient.getLock(detailKey);
        try {
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                TenantContextHolder.setTenantId(tradeDetailBase.getTenantId());
                checkVoucherVerify(tradeDetail, checkReqVO, tradeDetailBase);
                updateVoucherStatus(tradeDetail, checkReqVO, tradeDetailBase);
                respVO.setIsSuccess(1);
                respVO.setMsg("核销成功");
            } else {
                log.error("未获取到锁，核销子票失败 detailId:{}", tradeDetailBase.getId());
                throw exception(CHECK_PRODUCT_LOCK_ERROR, tradeDetailBase.getId());
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("核销子票[detailBaseId:{}]失败: {},", tradeDetailBase.getId(), e.getMessage());
            respVO.setMsg(e.getMessage());
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
        // 推送核销结果消息
        if (respVO.getIsSuccess() == 1) {
            tradePublishUtils.checkVoucherBaseSuccessMsg(tradeDetailBase.getId().toString());
        }
        // 核销操作记录
        Integer statusOld = null;
        Integer statusNew = null;
        if (respVO.getIsSuccess() == 1) {
            String s = updateOrderStatus(tradeDetail.getOrderId());
            String[] split = s.split(":");
            statusOld = Integer.valueOf(split[0]);
            statusNew = Integer.valueOf(split[1]);
        }
        TradeOrderLogUtils.setOrderInfo(tradeDetail.getOrderId(), statusOld, statusNew,
                buildExtMap(respVO, checkReqVO, tradeDetail.getCheckedDetailBaseNames()));
        return respVO;
    }

    @Override
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_CHECK)
    public TradeCheckRespVO checkOtherHandle(String checkCode, TradeCheckReqVO checkReqVO) {
        TenantContextHolder.setIgnore(true);
        TradeDetailDO detailDO =  tradeDetailMapper.selectOne(TradeDetailDO::getVoucherCode, checkCode);
        if (detailDO == null) {
            throw exception(TRADE_DETAIL_NOT_EXIST);
        }

        TradeCheckRespVO respVO = TradeCheckRespVO.builder()
                .targetType(CheckTargetTypeEnum.Voucher.getType())
                .targetId(detailDO.getId())
                .targetNo(detailDO.getVoucherCode())
                .isSuccess(0).isPreSuccess(0)
                .build();
        String detailKey = String.format(UPDATE_ORDER_LOCK, detailDO.getOrderId());
        RLock lock = redissonClient.getLock(detailKey);
        try {
            if (lock.tryLock(30, 60, TimeUnit.SECONDS)) {
                updateVoucherStatusWithSelfBuilt(detailDO, checkReqVO);
                respVO.setIsSuccess(1);
                respVO.setMsg("核销成功");
            } else {
                log.error("未获取到锁，核销(组合产品)门票失败 detailId:{}", detailDO.getId());
                throw exception(CHECK_PRODUCT_LOCK_ERROR, detailDO.getId());
            }
        } catch (Exception e) {
            log.error("核销门票(组合产品)[voucherCode:{}]失败: {}", detailDO.getVoucherCode(), e.getMessage());
            respVO.setMsg(e.getMessage());
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
        TenantContextHolder.setIgnore(false);
        // 推送核销结果消息
        if (respVO.getIsSuccess() == 1) {
            tradePublishUtils.checkVoucherSuccessMsg(detailDO.getId().toString());
        }

        // 核销操作记录
        Integer statusOld = null;
        Integer statusNew = null;
        if (respVO.getIsSuccess() == 1) {
            TenantContextHolder.setIgnore(true);
            String s = updateOrderStatus(detailDO.getOrderId());
            TenantContextHolder.setIgnore(false);
            String[] split = s.split(":");
            statusOld = Integer.valueOf(split[0]);
            statusNew = Integer.valueOf(split[1]);
        }
        TradeOrderLogUtils.setOrderInfo(detailDO.getOrderId(), statusOld, statusNew,
                buildExtMap(respVO, checkReqVO, detailDO.getCheckedDetailBaseNames()));
        return respVO;
    }

    /**
     * 修改门票状态
     *
     * @param tradeDetail     门票(组合产品)
     * @param checkReqVO      记录
     * @param tradeDetailBase 子票(基础产品)
     */
    private void updateVoucherStatus(TradeDetailDO tradeDetail, TradeCheckReqVO checkReqVO, TradeDetailBaseDO tradeDetailBase) {
        // 门票核销记录
        TradeCheckDO detailLog = BeanUtil.toBean(checkReqVO, TradeCheckDO.class);
        detailLog.setOrderId(tradeDetail.getOrderId());
        detailLog.setDetailId(tradeDetail.getId());
        detailLog.setOriginalStatus(tradeDetail.getVoucherStatus());
        detailLog.setVoucherCode(tradeDetail.getVoucherCode());
        tradeCheckMapper.insert(detailLog);
        checkVoucherStatus(tradeDetail, VoucherStatusEnum.VERIFIED.getStatus());
    }
    /**
     * 判断是否修改订单状态
     *
     * @param orderId 订单id
     * @return {原订单状态}:{订单状态}
     */
    private String updateOrderStatus(Long orderId) {
        TradeOrderDO tradeOrderDO = tradeOrderMapper.selectById(orderId);
        Integer originalOrderStatus = tradeOrderDO.getOrderStatus();
        int orderStatus;
        int count = tradeDetailMapper.selectNoCheckCount(orderId);
        if(count>0){
            orderStatus = TradeOrderStatusEnum.PART_CHECK.getStatus();
        }else{
            orderStatus = TradeOrderStatusEnum.ALL_CHECK.getStatus();
        }
        if(tradeOrderDO.getOrderStatus()!=orderStatus) {
            tradeOrderMapper.updateOrderStatus(orderId, orderStatus);
        }
        String result = String.format("%s:%d", originalOrderStatus, orderStatus);
        tradePublishUtils.updateOrderStatusMsg(orderId+"");
        return result;
    }

    /**
     * 修改门票状态
     * @param detailDO 门票
     */
    @TenantIgnore
    private void checkVoucherStatus(TradeDetailDO detailDO, int status) {
        TradeDetailDO updateDO = new TradeDetailDO();
        updateDO.setId(detailDO.getId());
        boolean flag = false;
        if(VoucherStatusEnum.canCheckForSub(detailDO.getVoucherStatus())){
            updateDO.setVoucherStatus(status);
            flag = true;
        }
        if (detailDO.getCheckStatus() == null || ObjectUtil.equal(detailDO.getCheckStatus(),0)) {
            updateDO.setCheckStatus(1);
            updateDO.setVerifyTime(LocalDateTime.now());
            flag = true;
        }
        if(flag){
            tradeDetailMapper.updateById(updateDO);
        }
    }

    /**
     * 修改门票状态（自建基础产品）
     *
     * @param tradeDetail     门票(组合产品)
     * @param checkReqVO      记录
     */
    private void updateVoucherStatusWithSelfBuilt(TradeDetailDO tradeDetail, TradeCheckReqVO checkReqVO) {
        // 门票核销记录
        TradeCheckDO detailLog = BeanUtil.toBean(checkReqVO, TradeCheckDO.class);
        detailLog.setOrderId(tradeDetail.getOrderId());
        detailLog.setDetailId(tradeDetail.getId());
        detailLog.setOriginalStatus(tradeDetail.getVoucherStatus());
        detailLog.setVoucherCode(tradeDetail.getVoucherCode());
        tradeCheckMapper.insert(detailLog);
        tradeDetailMapper.updateVoucherStatus(tradeDetail.getId(), VoucherStatusEnum.VERIFIED.getStatus());

    }

    public static void main(String[] args) {
        String startTime = "2025-03-12 00:00:00";
        System.out.println(DateUtil.compare(DateUtil.parseTime(startTime),new Date())>=0);
    }
}

