package com.yaoyicloud.config;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Redis 计数器工具类
 */
@Component
@RequiredArgsConstructor
public class RelationCounterRedisUtil {

    // Redis 键前缀（避免与其他缓存键冲突）
    private static final String COUNTER_KEY_PREFIX = "counter:";

    // Redis 模板（注入 String 类型的模板，计数以字符串形式存储）
    private final RedisTemplate<String, String> redisTemplate;
    private static final long DEF_REPORT_TTL = 1 * 60 * 60 * 1000;

    /**
     * 生成 Redis 计数器的完整 key
     *
     * @param relationId 业务关联 ID
     * @return 格式：relation:counter:{relationId}
     */
    private String getCounterKey(Long relationId) {
        return COUNTER_KEY_PREFIX + relationId;
    }

    /**
     * 初始化计数器
     * 注意：通常无需主动调用，increment 方法会自动处理不存在的键
     *
     * @param relationId 业务关联 ID
     */
    public void initCounter(Long relationId, int initialValue) {
        String key = getCounterKey(relationId);
        // 仅当键不存在时设置初始值为 0（避免覆盖已有计数）
        redisTemplate.opsForValue().setIfAbsent(key, String.valueOf(initialValue), DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
    }

    /**
     * 计数器自增 1，并返回自增后的值
     *
     * @param relationId 业务关联 ID
     * @return 自增后的计数（例如：初始为 0，调用后返回 1）
     */
    public int increment(Long relationId) {
        return increment(relationId, 1);
    }

    /**
     * 计数器自增指定步长，并返回自增后的值
     *
     * @param relationId 业务关联 ID
     * @param step       自增步长（正整数）
     * @return 自增后的计数
     */
    public int increment(Long relationId, int step) {
        if (step <= 0) {
            throw new IllegalArgumentException("自增步长必须为正整数");
        }
        String key = getCounterKey(relationId);
        // Redis 的 INCRBY 命令：原子性自增，返回自增后的值
        Long newValue = redisTemplate.opsForValue().increment(key, step);
        return newValue.intValue();
    }

    /**
     * 获取当前计数
     *
     * @param relationId 业务关联 ID
     * @return 当前计数（若键不存在，返回 0）
     */
    public Integer getCount(Long relationId) {
        String key = getCounterKey(relationId);
        String value = redisTemplate.opsForValue().get(key);
        String className = "";
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        if (stack.length >= 2) {
            StackTraceElement caller = stack[2];
            className = caller.getClassName();
        }
        if (value == null && className.contains("Cso")) {

            initCounter(relationId, 0);
            return 0;
        } else if (value == null && className.contains("Fxy")) {
            initCounter(relationId, 1);
            return 1;
        }

        return Integer.parseInt(value);
    }

    /**
     * 重置计数器为 0
     *
     * @param relationId 业务关联 ID
     */
    public void reset(Long relationId) {
        String key = getCounterKey(relationId);
        redisTemplate.opsForValue().set(key, "1", DEF_REPORT_TTL, TimeUnit.MILLISECONDS);
    }

    /**
     * 删除计数器（适用于业务结束后清理资源）
     *
     * @param relationId 业务关联 ID
     * @return 是否删除成功（true：键存在且被删除；false：键不存在）
     */
    public boolean delete(Long relationId) {
        String key = getCounterKey(relationId);
        return Boolean.TRUE.equals(redisTemplate.delete(key));
    }

    /**
     * 设置计数器过期时间（避免长期占用 Redis 内存）
     *
     * @param relationId 业务关联 ID
     * @param timeout    过期时间
     * @param unit       时间单位
     */
    public void setExpire(Long relationId, long timeout, TimeUnit unit) {
        String key = getCounterKey(relationId);
        redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 检查计数器是否存在
     *
     * @param relationId 业务关联 ID
     * @return true：存在；false：不存在
     */
    public boolean exists(Long relationId) {
        String key = getCounterKey(relationId);
        return Boolean.TRUE.equals(redisTemplate.hasKey(key));
    }
}
