package com.jy.framework.redis;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.jy.framework.config.JyConfig;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * redis缓存 工具类
 **/
@SuppressWarnings({"unchecked", "UnusedReturnValue", "rawtypes", "unused"})
public class RedisCache {

    private static final RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
    private static final JyConfig JY_CONFIG = SpringUtil.getBean(JyConfig.class);
    private static final String PREFIX = JY_CONFIG.getProjectName() + StringPool.COLON;

    /**
     * 设置缓存
     *
     * @param key   缓存键
     * @param value 缓存值
     */
    public static void set(String key, Object value) {
        redisTemplate.opsForValue().set(PREFIX + key, value);
    }

    /**
     * 设置缓存，并指定过期时间
     *
     * @param key      缓存键
     * @param value    缓存值
     * @param duration 时间
     */
    public static void set(String key, Object value, Duration duration) {
        redisTemplate.opsForValue().set(PREFIX + key, value, duration);
    }

    /**
     * 获取缓存
     *
     * @param key 缓存键
     * @param <T> 返回对象类型
     * @return 缓存值
     */
    public static <T> T get(String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(PREFIX + key);
    }

    /**
     * 删除缓存
     *
     * @param key 缓存键
     */
    public static void delete(String key) {
        redisTemplate.delete(PREFIX + key);
    }

    /**
     * 存活时间
     *
     * @param key 缓存键
     * @return 存活时间（毫秒）
     */
    public static Long getExpire(String key) {
        return redisTemplate.getExpire(PREFIX + key, TimeUnit.MILLISECONDS);
    }

    /**
     * 存活时间
     *
     * @param key      缓存键
     * @param timeUnit 时间粒度
     * @return 存活时间
     */
    public static Long getExpire(String key, TimeUnit timeUnit) {
        return redisTemplate.getExpire(PREFIX + key, timeUnit);
    }

    /**
     * 设置存活时间
     *
     * @param key      缓存键
     * @param duration 时间
     */
    public static void setExpire(String key, Duration duration) {
        redisTemplate.expire(PREFIX + key, duration);
    }

    /**
     * 原子自增
     *
     * @param key      缓存键
     * @param duration 时间
     * @return 自增数
     */
    public static Long incr(String key, Duration duration) {
        RedisConnectionFactory connectionFactory = redisTemplate.getRequiredConnectionFactory();
        RedisAtomicLong entityIdCounter = new RedisAtomicLong(PREFIX + key, connectionFactory);
        entityIdCounter.expire(duration);
        return entityIdCounter.incrementAndGet();
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 缓存键前缀
     * @return 对象列表
     */
    public static List<String> scan(String pattern) {
        return (List<String>) redisTemplate.execute((RedisCallback<List<String>>) connection -> {
            List<String> list = new ArrayList<>();
            ScanOptions scanOptions = ScanOptions.scanOptions().match(PREFIX + pattern).build();
            try (Cursor<byte[]> cursor = connection.keyCommands().scan(scanOptions)) {
                while (cursor.hasNext()) {
                    list.add(new String(cursor.next()).substring(PREFIX.length()));
                }
            }
            return list;
        });
    }

}
