package com.czg.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.czg.account.service.ShopTableService;
import com.czg.config.RedisCst;
import com.czg.enums.OrderNoPrefixEnum;
import com.czg.enums.ShopTableStatusEnum;
import com.czg.market.service.OrderInfoService;
import com.czg.order.entity.CashierCart;
import com.czg.order.entity.GbOrder;
import com.czg.order.entity.OrderInfo;
import com.czg.order.entity.OrderPayment;
import com.czg.constants.PayTypeConstants;
import com.czg.order.service.CashierCartService;
import com.czg.order.service.GbOrderService;
import com.czg.order.service.OrderPaymentService;
import com.czg.service.RedisService;
import com.czg.service.order.enums.OrderStatusEnums;
import com.czg.service.order.service.PayService;
import com.czg.utils.CzgRandomUtils;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单过期处理
 * 退款失败 补偿
 *
 * @author ww
 */
@Slf4j
@Component
public class OTimeTask {
    @Resource
    private OrderInfoService orderInfoService;
    @Resource
    private CashierCartService cartService;
    @Resource
    private OrderPaymentService paymentService;
    @Resource
    private GbOrderService gbOrderService;
    @Resource
    private PayService payService;
    @Resource
    private RedisService redisService;
    @DubboReference
    private ShopTableService shopTableService;

    /**
     * order 过期
     */
    @Scheduled(cron = "0 0 1 * * ? ")
    public void run() {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq(OrderInfo::getStatus, OrderStatusEnums.UNPAID.getCode())
                .lt(OrderInfo::getTradeDay, DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd"));
        List<OrderInfo> list = orderInfoService.list(queryWrapper);
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(orderInfo -> shopTableService.updateStatus(orderInfo.getShopId(), null, orderInfo.getTableCode(), ShopTableStatusEnum.IDLE.getValue()));
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setStatus(OrderStatusEnums.CANCELLED.getCode());
            orderInfoService.update(orderInfo, queryWrapper);
        }

        QueryWrapper cartUpdateWrapper = new QueryWrapper();
        cartUpdateWrapper.lt(CashierCart::getCreateTime, DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd HH:mm:ss"))
                .and(wrapper -> {
                    wrapper.isNull(CashierCart::getUpdateTime).or(CashierCart::getUpdateTime).lt(DateUtil.format(DateUtil.lastWeek(), "yyyy-MM-dd HH:mm:ss"));
                });
        cartService.remove(cartUpdateWrapper);
    }

    /**
     * 订单 过期 退钱
     * 每两小时 触发一次
     */
    @Scheduled(cron = "0 0 0/2 * * ?")
    public void gbOrderExpire() {
        // 当前系统时间
        LocalDateTime now = LocalDateTime.now();
        // 过期时间下限：当前时间往前推4小时（只查最近4小时内过期的）
        LocalDateTime expire4HoursAgo = now.minusHours(4);
        List<GbOrder> expiredOrderList = gbOrderService.list(QueryWrapper.create()
                .eq(GbOrder::getStatus, "ing")
                .le(GbOrder::getGroupEndTime, now)
                .ge(GbOrder::getGroupEndTime, expire4HoursAgo));

        // 处理已过期订单
        for (GbOrder expiredOrder : expiredOrderList) {
            //退款
            gbOrderService.expireRefund(null, expiredOrder);
        }

        //查询【当前时间往后2小时内】将要过期的订单
        LocalDateTime willExpire2HoursLater = now.plusHours(2);
        List<GbOrder> willExpireOrderList = gbOrderService.list(QueryWrapper.create()
                .eq(GbOrder::getStatus, "ing")
                .ge(GbOrder::getGroupEndTime, now)
                .le(GbOrder::getGroupEndTime, willExpire2HoursLater));
        // 处理将要过期订单（如推送提醒、催参团等）
        for (GbOrder willExpireOrder : willExpireOrderList) {
            LocalDateTime endTime = willExpireOrder.getGroupEndTime();
            Duration duration = Duration.between(now, endTime);
            long seconds = duration.getSeconds();
            redisService.set(RedisCst.classKeyExpired.EXPIRED_GB_ORDER + willExpireOrder.getId(), willExpireOrder.getId(), seconds);
        }
    }

    /**
     * 退钱补偿
     * 积分 和 拼团
     */
    @Scheduled(cron = "0 50 23 * * ? ")
    public void refundCompensate() {
        //积分 和 拼团
        List<String> ware = List.of(
                PayTypeConstants.SourceType.WARE,
                PayTypeConstants.SourceType.POINT,
                PayTypeConstants.SourceType.PP
        );

        LocalDateTime tenMinutesAgo = LocalDateTime.now().minusMinutes(10);
        LocalDateTime thirdDayAgo = LocalDateTime.now().minusDays(3);
        List<OrderPayment> list = paymentService.list(QueryWrapper.create()
                .gt(OrderPayment::getUpdateTime, thirdDayAgo)
                .lt(OrderPayment::getUpdateTime, tenMinutesAgo)
                .in(OrderPayment::getSourceType, ware)
                .eq(OrderPayment::getPayType, PayTypeConstants.PayType.REFUND)
                .ne(OrderPayment::getPayStatus, PayTypeConstants.PayStatus.SUCCESS));
        for (OrderPayment payment : list) {
            String refPayOrderNo = CzgRandomUtils.snowflake(OrderNoPrefixEnum.REP);
            payService.unifyRefund(payment, refPayOrderNo);
        }
    }
}
