package shop.alien.store.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import shop.alien.entity.store.UserReservationOrder;
import shop.alien.store.config.BaseRedisService;
import shop.alien.store.listener.RedisKeyExpirationHandler;
import shop.alien.store.service.ReservationOrderPaymentTimeoutService;
import shop.alien.store.service.UserReservationOrderService;

import javax.annotation.PostConstruct;
import java.util.Date;

/**
 * 预订订单支付超时服务实现：Redis 缓存 15 分钟，过期自动关闭订单
 *
 * @author system
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReservationOrderPaymentTimeoutServiceImpl implements ReservationOrderPaymentTimeoutService {

    private static final String REDIS_KEY_PREFIX = "reservation:order:payment:timeout:";
    /** 默认支付超时时间：15 分钟 */
    private static final long DEFAULT_TIMEOUT_SECONDS = 15 * 60;

    private final BaseRedisService redisService;
    private final RedisKeyExpirationHandler expirationHandler;
    private final UserReservationOrderService userReservationOrderService;

    @PostConstruct
    public void init() {
        expirationHandler.registerHandler(REDIS_KEY_PREFIX, this::onExpiredKey);
        log.info("预订订单支付超时处理器注册完成，前缀: {}，超时: {} 分钟", REDIS_KEY_PREFIX, DEFAULT_TIMEOUT_SECONDS / 60);
    }

    private void onExpiredKey(String expiredKey) {
        try {
            String orderSn = expiredKey.replace(REDIS_KEY_PREFIX, "");
            log.info("检测到预订订单支付超时，orderSn={}", orderSn);
            handleReservationOrderPaymentTimeout(orderSn);
        } catch (Exception e) {
            log.error("处理预订订单支付超时 key 失败，key={}", expiredKey, e);
        }
    }

    @Override
    public void setReservationOrderPaymentTimeout(String orderSn, long timeoutSeconds) {
        if (orderSn == null || orderSn.trim().isEmpty()) {
            log.warn("订单编号为空，无法设置支付超时");
            return;
        }
        long timeout = timeoutSeconds > 0 ? timeoutSeconds : DEFAULT_TIMEOUT_SECONDS;
        String key = REDIS_KEY_PREFIX + orderSn;
        redisService.setString(key, orderSn, timeout);
        log.info("设置预订订单支付超时，orderSn={}, 超时秒数={}, key={}", orderSn, timeout, key);
    }

    @Override
    public void cancelReservationOrderPaymentTimeout(String orderSn) {
        if (orderSn == null || orderSn.trim().isEmpty()) {
            return;
        }
        String key = REDIS_KEY_PREFIX + orderSn;
        redisService.delete(key);
        log.info("取消预订订单支付超时监听，orderSn={}, key={}", orderSn, key);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleReservationOrderPaymentTimeout(String orderSn) {
        if (orderSn == null || orderSn.trim().isEmpty()) {
            return;
        }
        UserReservationOrder order = userReservationOrderService.getByOrderSn(orderSn);
        if (order == null) {
            log.warn("预订订单不存在，orderSn={}", orderSn);
            return;
        }
        // 仅对待支付(0)状态关闭
        if (order.getOrderStatus() != null && order.getOrderStatus() == 0) {
            LambdaUpdateWrapper<UserReservationOrder> update = new LambdaUpdateWrapper<>();
            update.eq(UserReservationOrder::getOrderSn, orderSn)
                    .set(UserReservationOrder::getOrderStatus, 5) // 5:已关闭
                    .set(UserReservationOrder::getUpdatedTime, new Date());
            boolean ok = userReservationOrderService.update(update);
            if (ok) {
                log.info("预订订单支付超时已自动关闭，orderSn={}", orderSn);
            } else {
                log.error("关闭预订订单失败，orderSn={}", orderSn);
            }
        } else {
            log.info("预订订单非待支付状态，无需关闭，orderSn={}, status={}", orderSn, order.getOrderStatus());
        }
    }
}
