package com.njcn.msgpush.module.push.dal.redis;

import com.njcn.msgpush.module.push.dal.dataobject.message.MessageRecordDO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.ZoneId;
import java.util.Set;

/**
 * {@link com.njcn.msgpush.module.push.dal.dataobject.retry.MessageRetryQueueDO} RedisDAO
 *
 * @author caozehui
 * @data 2026-02-27
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MessageRetryRedisDAO {
    private final RedisTemplate<String, String> redisTemplate;

    /**
     * Redis中消息重试队列的Key前缀
     */
    private static final String RETRY_QUEUE_KEY_PREFIX = "msgpush:retry_queue:";

    /**
     * 获取指定渠道的重试队列Key
     */
    private String getRetryQueueKey(String channel) {
        return RETRY_QUEUE_KEY_PREFIX + channel;
    }

    /**
     * 添加消息到重试队列
     *
     * @param message 消息
     */
    public void addToRetryQueue(MessageRecordDO message) {
        String key = getRetryQueueKey(message.getChannel());
        double score = message.getNextRetryTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

        try {
            redisTemplate.opsForZSet().add(key, message.getMessageId(), score);
            log.debug("添加消息到重试队列成功: channel={}, messageId={}, nextRetryTime={}",
                    message.getChannel(), message.getMessageId(), message.getNextRetryTime());
        } catch (Exception e) {
            log.error("添加消息到重试队列失败: channel={}, messageId={}", message.getChannel(), message.getMessageId(), e);
            throw e;
        }
    }

    /**
     * 从重试队列移除消息
     *
     * @param channel   渠道类型
     * @param messageId 消息ID
     */
    public void removeFromRetryQueue(String channel, String messageId) {
        String key = getRetryQueueKey(channel);

        try {
            redisTemplate.opsForZSet().remove(key, messageId);
            log.debug("从重试队列移除消息成功: channel={}, messageId={}", channel, messageId);
        } catch (Exception e) {
            log.error("从重试队列移除消息失败: channel={}, messageId={}", channel, messageId, e);
        }
    }

    /**
     * 获取需要重试的消息ID集合
     *
     * @param channel     渠道类型
     * @param currentTime 当前时间戳
     * @param limit       限制数量
     * @return 消息ID集合
     */
    public Set<String> getNeedRetryMessageIds(String channel, long currentTime, int limit) {
        String key = getRetryQueueKey(channel);

        try {
            return redisTemplate.opsForZSet().rangeByScore(key, 0, currentTime, 0, limit);
        } catch (Exception e) {
            log.error("获取需要重试的消息ID失败: channel={}", channel, e);
            return null;
        }
    }

    /**
     * 获取队列大小
     *
     * @param channel 渠道类型
     * @return 队列大小
     */
    public Long getQueueSize(String channel) {
        String key = getRetryQueueKey(channel);

        try {
            return redisTemplate.opsForZSet().size(key);
        } catch (Exception e) {
            log.error("获取队列大小失败: channel={}", channel, e);
            return 0L;
        }
    }

    /**
     * 清空指定渠道的重试队列
     *
     * @param channel 渠道类型
     */
    public void clearRetryQueue(String channel) {
        String key = getRetryQueueKey(channel);

        try {
            redisTemplate.delete(key);
            log.info("清空重试队列成功: channel={}", channel);
        } catch (Exception e) {
            log.error("清空重试队列失败: channel={}", channel, e);
        }
    }
}
