package cn.ysk.cashier.service.impl.order;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.ysk.cashier.cons.TableConstant;
import cn.ysk.cashier.cons.rabbit.RabbitConstants;
import cn.ysk.cashier.dto.order.OrderCouponInfoDTO;
import cn.ysk.cashier.dto.order.TbOrderInfoDto;
import cn.ysk.cashier.dto.order.TbOrderInfoQueryCriteria;
import cn.ysk.cashier.dto.order.TbPayCountQueryCriteria;
import cn.ysk.cashier.exception.BadRequestException;
import cn.ysk.cashier.mapper.order.TbOrderInfoMapper;
import cn.ysk.cashier.mapper.product.TbProductMapper;
import cn.ysk.cashier.mapper.product.TbProductSkuMapper;
import cn.ysk.cashier.mybatis.entity.*;
import cn.ysk.cashier.mybatis.mapper.*;
import cn.ysk.cashier.mybatis.service.*;
import cn.ysk.cashier.mybatis.service.impl.MpOrderDetailServiceImpl;
import cn.ysk.cashier.pojo.TbShopPayType;
import cn.ysk.cashier.pojo.order.TbCashierCart;
import cn.ysk.cashier.pojo.order.TbFullOrderDetail;
import cn.ysk.cashier.pojo.order.TbOrderDetail;
import cn.ysk.cashier.pojo.order.TbOrderInfo;
import cn.ysk.cashier.pojo.product.TbProduct;
import cn.ysk.cashier.pojo.shop.TbMerchantThirdApply;
import cn.ysk.cashier.pojo.shop.TbShopInfo;
import cn.ysk.cashier.pojo.shop.TbShopUser;
import cn.ysk.cashier.repository.TbShopPayTypeRepository;
import cn.ysk.cashier.repository.order.TbCashierCartRepository;
import cn.ysk.cashier.repository.order.TbOrderDetailRepository;
import cn.ysk.cashier.repository.order.TbOrderInfoRepository;
import cn.ysk.cashier.repository.product.TbProductSkuRepository;
import cn.ysk.cashier.repository.shop.TbMerchantThirdApplyRepository;
import cn.ysk.cashier.service.PayService;
import cn.ysk.cashier.service.order.TbOrderInfoService;
import cn.ysk.cashier.service.product.TbProductService;
import cn.ysk.cashier.thirdpay.resp.OrderStatusQueryResp;
import cn.ysk.cashier.thirdpay.resp.PublicResp;
import cn.ysk.cashier.thirdpay.service.ThirdPayService;
import cn.ysk.cashier.utils.*;
import cn.ysk.cashier.vo.TbOrderInfoVo;
import cn.ysk.cashier.vo.TbOrderPayCountVo;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author lyf
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2024-03-02
 **/
@Slf4j
@Service
@RequiredArgsConstructor
public class TbOrderInfoServiceImpl implements TbOrderInfoService {

    private final TbOrderInfoRepository tbOrderInfoRepository;
    private final TbOrderInfoMapper tbOrderInfoMapper;
    private final cn.ysk.cashier.mybatis.mapper.TbOrderInfoMapper orderInfoMapper;

    private final TbOrderDetailRepository tbOrderDetailRepository;
    private final TbShopPayTypeRepository payTypeRepository;
    private final TbProductService productService;
    private final TbOrderPaymentService paymentService;
    private final TbMerchantThirdApplyRepository thirdApplyRepository;
    private final RedisUtils redisUtils;
    private final ThirdPayService thirdPayService;
    private final TbCashierCartRepository cartRepository;
    private final TbActivateInRecordService inRecordService;
    private final TbActivateOutRecordService outRecordService;
    private final RabbitTemplate rabbitTemplate;
    private final TbMShopUserMapper tbMShopUserMapper;
    private final TbShopUserFlowMapper tbShopUserFlowMapper;
    private final RabbitMsgUtils rabbitMsgUtils;

    private final PayService payService;
    private final TbOrderDetailMapper tbOrderDetailMapper;
    private final MpCashierCartService mpCashierCartService;
    private final MpShopInfoMapper mpShopInfoMapper;
    private final TbMemberPointsService memberPointsService;
    private final TbShopCouponService shopCouponService;
    private final MpOrderDetailService mpOrderDetailService;

    @Value("${thirdPay.url}")
    private String url;

    @Override
    public Map<String, Object> queryAllPage(TbOrderInfoQueryCriteria criteria) {
        Pageable pageable = PageRequest.of(criteria.getPage(), criteria.getPageSize(), Sort.by(Sort.Direction.DESC, "createdAt"));
        if (criteria != null) {
            if (StringUtils.isNotBlank(criteria.getOrderType()) && criteria.getOrderType().equals("0")) {
                criteria.setOrderType(null);
            }
        }
        Page<TbOrderInfo> page = tbOrderInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> {
            Predicate predicate = QueryHelp.getPredicate(root, criteria, criteriaBuilder);
            // 追加校验参数 status不为空 且 source不为空 不查询状态为 "refund" 的
            if (StringUtils.isBlank(criteria.getStatus()) && StringUtils.isBlank(criteria.getSource())) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.notEqual(root.get("orderType"), "return"));
            }

            if (criteria.getUserId() != null && criteria.getUserId() != 0) {
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.equal(root.get("userId"), criteria.getUserId()));
            }

            if (StringUtils.isNotBlank(criteria.getKeyword())) {
                Date startTime, endTime;
                DateTime offsetMonth = cn.hutool.core.date.DateUtil.offsetMonth(new Date(), 3);
                if (criteria.getCreatedAt() != null && criteria.getCreatedAt().size() == 2) {
                    if (criteria.getCreatedAt().get(0) < System.currentTimeMillis() - 1000 * 60 * 60 * 24 * 90L) {
                        throw new BadRequestException("查询时间范围不能超过三个月");
                    }
                    Long startLong = criteria.getCreatedAt().get(0);
                    Long endLong = criteria.getCreatedAt().get(1);

                    startTime = new Date(startLong);
                    endTime = new Date(endLong);
                } else {
                    startTime = offsetMonth;
                    endTime = new Date();
                }

                List<Integer> productIds = tbOrderDetailRepository.findOrderIdsByProductNameLike(criteria.getKeyword(),
                        criteria.getShopId(), startTime, endTime);
                Predicate inIds;

                if (productIds.isEmpty()) {
                    productIds.add(0);
                    inIds = root.get("id").in(productIds);
                } else {
                    inIds = root.get("id").in(productIds);
                }
                Predicate likeOrderNo = criteriaBuilder.like(root.get("orderNo"), "%" + criteria.getKeyword() + "%");
                predicate = criteriaBuilder.and(predicate, criteriaBuilder.or(likeOrderNo, inIds));

            }

            return predicate;
        }, pageable);

        List<String> shopIds = page.getContent().stream().map(TbOrderInfo::getShopId).distinct().collect(Collectors.toList());
        HashMap<String, TbShopInfo> shopInfoMap = new HashMap<>();
        if (!shopIds.isEmpty()) {
            mpShopInfoMapper.selectBatchIds(shopIds).forEach(item -> {
                shopInfoMap.put(item.getId().toString(), item);
            });
        }
        List<Object> orderInfoVoList = new ArrayList<>();
        for (TbOrderInfo tbOrderInfo : page.getContent()) {
            TbOrderInfoVo orderInfoVo = new TbOrderInfoVo();
            BigDecimal refundAmount = BigDecimal.ZERO;
            List<TbFullOrderDetail> details = tbOrderDetailMapper.selectFullInfoByOrderId(tbOrderInfo.getId());
            if (!tbOrderInfo.getOrderType().equals("return")) {
                List<TbOrderInfo> tbOrderInfos = tbOrderInfoRepository.selTbOrdersBysource(tbOrderInfo.getId(), tbOrderInfo.getShopId());
                Map<Integer, BigDecimal> map;
                if (!CollectionUtils.isEmpty(tbOrderInfos)) {
                    List<Integer> ids = tbOrderInfos.stream().map(TbOrderInfo::getId).collect(Collectors.toList());
                    List<TbOrderDetail> refundOrderDetail = tbOrderDetailRepository.searchDetailByOrderIds(ids);
                    map = refundOrderDetail.stream()
                            .collect(Collectors.groupingBy(
                                    TbOrderDetail::getProductSkuId,
                                    Collectors.reducing(
                                            BigDecimal.ZERO,
                                            TbOrderDetail::getNum,
                                            BigDecimal::add
                                    )
                            ));

                    refundAmount = tbOrderInfos.stream().map(TbOrderInfo::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                } else {
                    map = new HashMap<>();
                }
                details.parallelStream().forEach(detail -> {
                    BigDecimal refundNumber = map.get(detail.getProductSkuId());
                    if (refundNumber != null) {
                        detail.setRefundNumber(refundNumber);
                    }
                });
            } else {
                details.parallelStream().forEach(detail -> {
                    detail.setRefundNumber(detail.getNum());
                });
            }

            TbOrderDetail seatInfo = null;
            ArrayList<TbFullOrderDetail> detailList = new ArrayList<>();
            for (TbFullOrderDetail detail : details) {
                if (detail.getProductId() != null && TableConstant.CART_SEAT_ID.equals(detail.getProductId().toString())) {
                    seatInfo = detail;
                } else {
                    detailList.add(detail);
                }
            }
            orderInfoVo.setTableName(tbOrderInfo.getTableName());
            orderInfoVo.setDetailList(detailList);
            orderInfoVo.setSeatInfo(seatInfo);
            orderInfoVo.setRefundAmount(refundAmount);
            TbShopInfo shopInfo = shopInfoMap.get(tbOrderInfo.getShopId());
            if (shopInfo != null) {
                orderInfoVo.setRegisterType(shopInfo.getRegisterType());
            }
            Map<String, Object> map = BeanUtil.beanToMap(tbOrderInfo, false, false);
            Map<String, Object> objectMap = BeanUtil.beanToMap(orderInfoVo, false, false);
            objectMap.putAll(map);
            orderInfoVoList.add(objectMap);
        }
        return PageUtil.toPage(orderInfoVoList, page.getTotalElements());
    }

    @Override
    public List<TbOrderPayCountVo> queryTbOrderPayCount(TbPayCountQueryCriteria criteria) {
        List<TbOrderPayCountVo> result = new ArrayList<>();
        List<Long> createdAt = criteria.getCreatedAt();
        // 指定时间，例如2024年1月1日 00:00:00
        Long start = 1704038400000L;
        Long end = Instant.now().toEpochMilli();
        if (!CollectionUtils.isEmpty(createdAt)) {
            if (createdAt.get(0) > createdAt.get(1)) {
                start = createdAt.get(1);
                end = createdAt.get(0);
            } else {
                start = createdAt.get(0);
                end = createdAt.get(1);
            }
        }
        if (ObjectUtil.isEmpty(criteria.getTableName())) {
            criteria.setTableName(null);
        }
        List<TbOrderPayCountVo> payCountVoList = tbOrderInfoRepository.queryTbOrderPayCount(criteria.getShopId(), criteria.getTableName(), start, end);
        BigDecimal totalPayAmount = BigDecimal.ZERO;
        for (TbOrderPayCountVo payCount : payCountVoList) {
            totalPayAmount = totalPayAmount.add(new BigDecimal(payCount.getPayAmount().toString()));
            if (StringUtils.isNotBlank(payCount.getPayType())) {
                TbShopPayType byPayType = payTypeRepository.findByPayType(payCount.getPayType(), criteria.getShopId());
                if (byPayType != null) {
                    payCount.setPayType(byPayType.getPayName());
                    payCount.setIcon(byPayType.getIcon());
                }
                if (payCount.getPayType().equals("wx_lite")) {
                    payCount.setPayType("微信小程序支付");
                    payCount.setIcon("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240318/ecf9e234aad8426ab0b1c4d5b8e50c9d.jpg");
                }
                result.add(payCount);
            }
        }
        TbOrderPayCountVo payRufund = tbOrderInfoRepository.queryTbOrderRefund(criteria.getShopId(), criteria.getTableName(), start, end);
        if (payRufund != null) {
            totalPayAmount = totalPayAmount.subtract(new BigDecimal(payRufund.getPayAmount().toString()));
            payRufund.setPayType("退单");
            payRufund.setIcon("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240319/5741608662244b878762c61bb37c95c9.png");
            result.add(payRufund);
        }
        result.add(0, new TbOrderPayCountVo("https://cashier-oss.oss-cn-beijing.aliyuncs.com/upload/20240625/fa0e5b24884d4ac2a18973b3855e5309.png", "总金额", null, totalPayAmount));
        return result;
    }

    @Override
    public List<TbOrderInfoDto> queryAll(TbOrderInfoQueryCriteria criteria) {
        if (criteria != null) {
            if (StringUtils.isNotBlank(criteria.getOrderType()) && criteria.getOrderType().equals("0")) {
                criteria.setOrderType(null);
            }
        }

        List<TbOrderInfoDto> dto = tbOrderInfoMapper.toDto(tbOrderInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
        for (TbOrderInfoDto tbOrderInfo : dto) {
            List<TbOrderDetail> details = tbOrderDetailRepository.searchDetailByOrderId(tbOrderInfo.getId());
            tbOrderInfo.setDetailList(details);
        }
        return dto;
    }

    @Override
    @Transactional
    public Map<String, Object> findById(Integer id) {
        TbOrderInfo tbOrderInfo = tbOrderInfoRepository.findById(id).orElseGet(TbOrderInfo::new);
        ValidationUtil.isNull(tbOrderInfo.getId(), "TbOrderInfo", "id", id);
        TbOrderInfoDto dto = tbOrderInfoMapper.toDto(tbOrderInfo);
        if (StringUtils.isNotBlank(dto.getPayType())) {
            switch (dto.getPayType()) {
                case "scanCode":
                    dto.setPayType("扫码支付");
                    break;
                case "cash":
                    dto.setPayType("现金");
                    break;
                case "wx_lite":
                    dto.setPayType("微信小程序支付");
                    break;
                case "deposit":
                    dto.setPayType("储值卡支付");
                    break;
                default:
                    dto.setPayType(tbOrderInfo.getSendType());
                    break;
            }
        } else {
            if (dto.getStatus().equals("refund")) {
                dto.setPayType("退单");
            }
        }
        List<TbFullOrderDetail> details = tbOrderDetailMapper.selectFullInfoByOrderId(tbOrderInfo.getId());
        dto.setIsRefund(0);
        dto.setRefundAmount(BigDecimal.ZERO);
        dto.setRefundRemark(tbOrderInfo.getRefundRemark());
//        List<TbOrderInfo> tbOrderInfos = tbOrderInfoRepository.selTbOrdersBysource(tbOrderInfo.getId(), tbOrderInfo.getShopId());
//        if (!CollectionUtils.isEmpty(tbOrderInfos)) {
//            dto.setIsRefund(1);
//            dto.setRefundAmount(tbOrderInfos.stream().map(TbOrderInfo::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add));
//        }
        dto.setDetailList(details);
        List<TbOrderDetail> tbCashierCarts = tbOrderDetailMapper.selectList(new LambdaQueryWrapper<TbOrderDetail>()
                .eq(TbOrderDetail::getOrderId, id)
                .eq(TbOrderDetail::getProductId, TableConstant.CART_SEAT_ID)
                .orderByDesc(TbOrderDetail::getId));
        TbOrderDetail cashierDetail = tbCashierCarts.isEmpty() ? null : tbCashierCarts.get(0);
        dto.setSeatInfo(cashierDetail);
        Map<String, Object> data = BeanUtil.beanToMap(tbOrderInfo, false, false);
        data.putAll(BeanUtil.beanToMap(dto, false, false));
        data.put("refundAmount", tbOrderInfo.getRefundAmount());
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TbOrderInfoDto create(TbOrderInfo resources) {
        return tbOrderInfoMapper.toDto(tbOrderInfoRepository.save(resources));
    }

    @Async
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void expired(String orderId) {
        //修改耗材数据
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("type", "delete");
        TbOrderInfo tbOrderInfo = tbOrderInfoRepository.findById(Integer.valueOf(orderId)).orElse(null);
        if (tbOrderInfo != null) {
            if (tbOrderInfo.getStatus().equals("unpaid")) {
                upOrderStatus(tbOrderInfo);
                jsonObject1.put("orderId", tbOrderInfo.getId());
                // 发送取消订单mq消息
                rabbitTemplate.convertAndSend(RabbitConstants.CONS_COLLECT_PUT, RabbitConstants.CONS_COLLECT_ROUTINGKEY_PUT,
                        jsonObject1.toJSONString(), new CorrelationData(UUID.randomUUID().toString()));
            } else if (tbOrderInfo.getStatus().equals("paying") &&
                    (StringUtils.isBlank(tbOrderInfo.getPayType()) ||
                            !tbOrderInfo.getPayType().equals("deposit"))) {
                QueryWrapper<TbOrderPayment> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("order_id", tbOrderInfo.getId());
                TbOrderPayment payment = paymentService.getOne(queryWrapper);
                if (payment != null && StringUtils.isNotBlank(payment.getTradeNumber())) {
                    if (System.currentTimeMillis() - payment.getCreatedAt() < 60 * 2 * 1000L) {
                        modfiyOrderInfo(tbOrderInfo);
                        redisUtils.set(CacheKey.ORDER_EXPIRED + tbOrderInfo.getId(), tbOrderInfo.getId(), 60 * 2);
                    } else {
                        upOrderStatus(tbOrderInfo);
                        jsonObject1.put("orderId", tbOrderInfo.getId());

                        // 发送取消订单mq消息
                        rabbitTemplate.convertAndSend(RabbitConstants.CONS_COLLECT_PUT, RabbitConstants.CONS_COLLECT_ROUTINGKEY_PUT,
                                jsonObject1.toJSONString(), new CorrelationData(UUID.randomUUID().toString()));
                    }
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void modfiyOrderInfo(TbOrderInfo tbOrderInfo) {
        QueryWrapper<TbOrderPayment> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", tbOrderInfo.getId());
        TbOrderPayment payment = paymentService.getOne(queryWrapper);
        if (ObjectUtil.isNotEmpty(payment) && ObjectUtil.isNotEmpty(payment.getTradeNumber())) {
            TbMerchantThirdApply thirdApply = thirdApplyRepository.getById(Integer.valueOf(tbOrderInfo.getMerchantId()));
            if (ObjectUtil.isEmpty(thirdApply) || ObjectUtil.isNull(thirdApply)) {
                //支付通道不存在
            }
            PublicResp<OrderStatusQueryResp> publicResp = thirdPayService.queryOrder(url, thirdApply.getAppId(), payment.getTradeNumber(), null, thirdApply.getAppToken());
            if (ObjectUtil.isNotNull(publicResp) && ObjectUtil.isNotEmpty(publicResp)) {
                if ("000000".equals(publicResp.getCode())) {
                    String cartStatus = "";
                    switch (publicResp.getObjData().getState()) {
                        case "TRADE_SUCCESS":
                            //修改数据库中购物车数据
                            cartRepository.updateToFinal(tbOrderInfo.getId());
                            //更新子单状态
                            tbOrderDetailRepository.updateToClosed(tbOrderInfo.getId());
                            //修改主单状态
                            tbOrderInfo.setStatus("closed");
                            tbOrderInfo.setPayType("wx_lite");
                            tbOrderInfo.setPayOrderNo(payment.getTradeNumber());
                            tbOrderInfo.setPayAmount(tbOrderInfo.getOrderAmount());
                            tbOrderInfoRepository.save(tbOrderInfo);
//                            JSONObject jsonObject = new JSONObject();
//                            jsonObject.put("token", 0);
//                            jsonObject.put("type", "wxcreate");
//                            jsonObject.put("orderId", orderInfo.getId().toString());
//                            producer.putOrderCollect(jsonObject.toJSONString());
//                            log.info("发送打印数据");
//                            producer.printMechine(orderInfo.getId() + "");
                    }
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void upOrderStatus(TbOrderInfo tbOrderInfo) {
        tbOrderInfo.setStatus("cancelled");
        //订单取消 赠送商品数量返回
        QueryWrapper<TbActivateOutRecord> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_id", tbOrderInfo.getId());
        queryWrapper.eq("status", "create");
        List<TbActivateOutRecord> outRecords = outRecordService.list(queryWrapper);
        for (TbActivateOutRecord outRecord : outRecords) {
            TbActivateInRecord inRecord = inRecordService.getById(outRecord.getGiveId());
            inRecord.setOverNum(inRecord.getOverNum() + outRecord.getUseNum());
            inRecordService.updateById(inRecord);
        }
        LambdaUpdateWrapper<TbActivateOutRecord> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(TbActivateOutRecord::getOrderId, tbOrderInfo.getId())
                .eq(TbActivateOutRecord::getStatus, "create")
                .set(TbActivateOutRecord::getStatus, "cancel");
        outRecordService.update(lambdaUpdateWrapper);

        List<TbOrderDetail> details = tbOrderDetailRepository.searchDetailByOrderId(tbOrderInfo.getId());
        Set<String> keys = new HashSet<>();
        for (TbOrderDetail detail : details) {
            detail.setStatus("cancelled");
            // 返还库存
            productService.returnStockByPro(detail.getProductId(), detail.getProductSkuId(), detail.getNum());
            tbOrderDetailRepository.save(detail);
            keys.add(CacheKey.PRODUCT_SKU + detail.getShopId() + ":" + detail.getId());
        }

        // 查询是否消耗了积分优惠券返还对应的卷或商品
        if (tbOrderInfo.getCouponInfoList() != null) {
            OrderCouponInfoDTO couponInfoDTO = JSONObject.parseObject(tbOrderInfo.getCouponInfoList(), OrderCouponInfoDTO.class);
            // 券返还
            if (!couponInfoDTO.getOutRecordList().isEmpty()) {
                couponInfoDTO.getOutRecordList().forEach(item -> {
                    item.setRefNum(item.getUseNum());
                });
                shopCouponService.refund(couponInfoDTO.getOutRecordList());
                couponInfoDTO.setOutRecordList(new ArrayList<>());
                tbOrderInfo.setCouponInfoList(null);
            }
        }

        // 返还积分
        if (tbOrderInfo.getPointsNum() != null && tbOrderInfo.getPointsNum() != 0 && tbOrderInfo.getMemberId() != null) {
            memberPointsService.addPoints(Long.valueOf(tbOrderInfo.getMemberId()), tbOrderInfo.getPointsNum(),
                    "订单取消返还: " + tbOrderInfo.getPointsNum() + "积分", Long.valueOf(tbOrderInfo.getId()));
        }

        mpCashierCartService.updateStateByOrderId(TableConstant.OrderInfo.Status.CLOSED, tbOrderInfo.getId());
        String[] keysArray = keys.toArray(new String[keys.size()]);
        redisUtils.del(keysArray);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(TbOrderInfo resources) {
        TbOrderInfo tbOrderInfo = tbOrderInfoRepository.findById(resources.getId()).orElseGet(TbOrderInfo::new);
        ValidationUtil.isNull(tbOrderInfo.getId(), "TbOrderInfo", "id", resources.getId());
        tbOrderInfo.copy(resources);
        tbOrderInfoRepository.save(tbOrderInfo);
    }

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            tbOrderInfoRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<TbOrderInfoDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();

        all = all.stream().sorted(Comparator.comparing(TbOrderInfoDto::getId).reversed()).collect(Collectors.toList());
        for (TbOrderInfoDto tbOrderInfo : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("订单编号", tbOrderInfo.getOrderNo());
            switch (tbOrderInfo.getOrderType()) {
                case "cash":
                    tbOrderInfo.setOrderType("收银");
                    break;
                case "miniapp":
                    tbOrderInfo.setOrderType("小程序");
                    break;
                case "offline":
                    tbOrderInfo.setOrderType("线下");
                    break;
                case "return":
                    tbOrderInfo.setOrderType("退单");
                    break;
                default:
                    tbOrderInfo.setOrderType(tbOrderInfo.getOrderType() + "未知订单类型");
                    break;
            }
            map.put("订单类型", tbOrderInfo.getOrderType());
            switch (tbOrderInfo.getSendType()) {
                case "post":
                    tbOrderInfo.setSendType("快递");
                    break;
                case "takeaway":
                    tbOrderInfo.setSendType("外卖");
                    break;
                case "takeself":
                    tbOrderInfo.setSendType("自提");
                    break;
                case "table":
                    tbOrderInfo.setSendType("堂食");
                    break;
                default:
                    tbOrderInfo.setSendType(tbOrderInfo.getSendType() + "未知送货类型");
                    break;
            }
            map.put("发货类型", tbOrderInfo.getSendType());
            // 商品信息
            String productNames = tbOrderInfo.getDetailList().stream()
                    .map(TbOrderDetail::getProductName)
                    .distinct()
                    .collect(Collectors.joining("/"));
            map.put("商品信息", productNames);
            //

            if (ObjectUtil.isNotEmpty(tbOrderInfo.getPayType()) && ObjectUtil.isNotNull(tbOrderInfo.getPayType())) {
                switch (tbOrderInfo.getPayType()) {
                    case "scanCode":
                        tbOrderInfo.setPayType("收款码支付");
                        break;
                    case "deposit":
                        tbOrderInfo.setPayType("会员卡支付");
                        break;
                    case "cash":
                        tbOrderInfo.setPayType("现金支付");
                        break;
                    case "wx_lite":
                        tbOrderInfo.setPayType("微信支付");
                        break;

                }
            } else {
                tbOrderInfo.setPayType("");
            }


            map.put("支付类型", tbOrderInfo.getPayType());
            map.put("订单金额", tbOrderInfo.getOrderAmount());
            map.put("支付金额", tbOrderInfo.getPayAmount());
            switch (tbOrderInfo.getStatus()) {
                case "unpaid":
                    tbOrderInfo.setStatus("待支付");
                    break;
                case "unsend":
                    tbOrderInfo.setStatus("待发货");
                    break;
                case "closed":
                    tbOrderInfo.setStatus("订单完成");
                    break;
                case "send":
                    tbOrderInfo.setStatus("已发货");
                    break;
                case "refunding":
                    tbOrderInfo.setStatus("申请退单中");
                    break;
                case "refund":
                    map.put("支付金额", "-" + tbOrderInfo.getPayAmount());
                    tbOrderInfo.setStatus("退单完成");
                    break;
                case "cancelled":
                    tbOrderInfo.setStatus("取消订单");
                    break;
                case "merge":
                    tbOrderInfo.setStatus("合台");
                    break;
                case "pending":
                    tbOrderInfo.setStatus("挂单");
                    break;
                case "activate":
                    tbOrderInfo.setStatus("激活订单");
                    break;
                default:
                    tbOrderInfo.setStatus(tbOrderInfo.getStatus() + "未知订单状态");
                    break;
            }
            map.put("状态", tbOrderInfo.getStatus());
            map.put("创建日期", DateUtil.timeStampFormatyMdHms(tbOrderInfo.getCreatedAt()));
            map.put("备注", tbOrderInfo.getRemark());
            map.put("台桌", tbOrderInfo.getTableName());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void depositReturn(Integer userId, Integer shopId, BigDecimal returnAmount) {
        TbShopUser user = tbMShopUserMapper.selectOne(new LambdaQueryWrapper<TbShopUser>()
                .eq(TbShopUser::getShopId, shopId)
                .eq(TbShopUser::getUserId, userId));
        if (user == null) {
            throw new BadRequestException("用户信息不存在");
        }
        tbMShopUserMapper.incrBalance(user.getId(), shopId, returnAmount, cn.hutool.core.date.DateUtil.current());

        TbShopUserFlow flow = new TbShopUserFlow();
        flow.setShopUserId(user.getId());
        flow.setBizCode("accountReturnPay");
        flow.setBizName("会员储值卡退款");
        flow.setType("+");
        flow.setAmount(returnAmount);
        flow.setBalance(user.getAmount());
        flow.setCreateTime(cn.hutool.core.date.DateUtil.date().toTimestamp());
        flow.setIsReturn("0");
        tbShopUserFlowMapper.insert(flow);

        JSONObject baObj = new JSONObject();
        baObj.put("userId", user.getUserId());
        baObj.put("shopId", user.getShopId());
        baObj.put("amount", returnAmount);
        baObj.put("balance", user.getAmount());
        baObj.put("type", "退款");
        baObj.put("time", flow.getCreateTime());
        rabbitMsgUtils.addBalanceRecord(baObj);
//        producer.balance(baObj.toString());
    }

    @Override
    public void successPay(Map<String, String> req) {
        JSONObject bizData = JSONObject.parseObject(req.get("bizData"));
        if ("000000".equals(req.get("code")) &&
                "TRADE_SUCCESS".equals(bizData.getString("state"))) {
            String payOrderId = bizData.get("payOrderId").toString();
            TbOrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<TbOrderInfo>()
                    .eq(TbOrderInfo::getPayOrderNo, payOrderId));
            if (orderInfo == null) {
                log.warn("订单信息不存在: {}", payOrderId);
                return;
            }
            payService.checkPayState(orderInfo);
        }
    }

    @Override
    public void successReturn(Map<String, String> req) {
        JSONObject bizData = JSONObject.parseObject(req.get("bizData"));
        if ("000000".equals(req.get("code")) &&
                "SUCCESS".equals(bizData.getString("state"))) {
            String payOrderId = bizData.get("payOrderId").toString();
            TbOrderInfo orderInfo = orderInfoMapper.selectOne(new LambdaQueryWrapper<TbOrderInfo>()
                    .eq(TbOrderInfo::getPayOrderNo, payOrderId));
            if (orderInfo == null) {
                log.warn("订单信息不存在: {}", payOrderId);
                return;
            }
            TbOrderInfo returnOrder = orderInfoMapper.selectOne(new LambdaQueryWrapper<TbOrderInfo>()
                    .eq(TbOrderInfo::getStatus, "refunding")
                    .eq(TbOrderInfo::getSource, orderInfo.getId()));
            if (returnOrder == null) {
                log.warn("订单信息不存在: {}", payOrderId);
                return;
            }
            returnOrder.setStatus("refund");
            returnOrder.setPaidTime(cn.hutool.core.date.DateUtil.current());
            orderInfoMapper.updateById(returnOrder);
        }
    }

    @Override
    public void cancelOrder() {
        List<TbOrderInfo> tbOrderInfos = orderInfoMapper.selectList(new LambdaQueryWrapper<TbOrderInfo>()
                .eq(TbOrderInfo::getStatus, "unpaid")
                .and(q -> q.and(qu -> qu.eq(TbOrderInfo::getUseType, TableConstant.OrderInfo.UseType.DINE_IN_AFTER.getValue()).lt(TbOrderInfo::getCreatedAt, cn.hutool.core.date.DateUtil.current() - 12 * 60 * 60 * 1000))
                        .or(qu -> qu.ne(TbOrderInfo::getUseType, TableConstant.OrderInfo.UseType.DINE_IN_AFTER.getValue())
                                .lt(TbOrderInfo::getCreatedAt, cn.hutool.core.date.DateUtil.current() - 15 * 60 * 1000))));
        log.info("超时订单: {}", tbOrderInfos);
        tbOrderInfos.parallelStream().forEach(orderInfo -> {
            try {
                // 查询是否消耗了积分优惠券返还对应的卷或商品
                if (orderInfo.getCouponInfoList() != null) {
                    OrderCouponInfoDTO couponInfoDTO = JSONObject.parseObject(orderInfo.getCouponInfoList(), OrderCouponInfoDTO.class);
                    // 券返还
                    if (!couponInfoDTO.getOutRecordList().isEmpty()) {
                        couponInfoDTO.getOutRecordList().forEach(item -> {
                            item.setRefNum(item.getUseNum());
                        });
                        shopCouponService.refund(couponInfoDTO.getOutRecordList());
                        couponInfoDTO.setOutRecordList(new ArrayList<>());
                        orderInfo.setCouponInfoList(null);
                    }
                }

                // 返还积分
                if (orderInfo.getPointsNum() != null && orderInfo.getPointsNum() != 0 && orderInfo.getMemberId() != null) {
                    memberPointsService.addPoints(Long.valueOf(orderInfo.getMemberId()), orderInfo.getPointsNum(), "订单取消返还: " + orderInfo.getPointsNum() + "积分", Long.valueOf(orderInfo.getId()));
                }

            } catch (Exception e) {
                log.error("返还订单积分优惠券失败: 订单信息: {}", orderInfo);
                log.error("异常信息: ", e);
            }finally {
                mpCashierCartService.updateStateByOrderId(TableConstant.OrderInfo.Status.CLOSED, orderInfo.getId());
                mpOrderDetailService.updateStatusByOrderId(TableConstant.OrderInfo.Status.CLOSED, orderInfo.getId());

                // 修改订单信息
                orderInfoMapper.update(null, new LambdaUpdateWrapper<TbOrderInfo>()
                        .eq(TbOrderInfo::getId, orderInfo.getId())
                        .eq(TbOrderInfo::getStatus, "unpaid")
                        .set(TbOrderInfo::getCouponInfoList, null)
                        .set(TbOrderInfo::getPointsNum, 0)
                        .set(TbOrderInfo::getUpdatedAt, cn.hutool.core.date.DateUtil.current())
                        .set(TbOrderInfo::getStatus, "cancelled"));
            }
        });
//        List<Integer> ids = tbOrderInfos.stream().map(TbOrderInfo::getId).collect(Collectors.toList());

    }
}
