package com.ruoyi.common.utils;

import org.redisson.api.*;
import org.redisson.api.options.KeysScanParams;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.ScoredEntry;

import java.time.Duration;
import java.util.*;

/**
 * Redis操作
 * @author ruoyi
 */
public class RedisUtil {

    RedissonClient redissonClient;

    public RedisUtil(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    // ============================================= string ============================================================
    /**
     * 缓存基本的对象，String、Integer、实体类等
     * @param key 缓存的键值
     * @param value 缓存的值
     */
    public <T> void setCacheObject(final String key, final T value) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value);
    }

    /**
     * 缓存基本的对象，String、Integer、实体类等
     * @param key 缓存的键值
     * @param value 缓存的值
     * @param duration 有效时间
     */
    public <T> void setCacheObject(final String key, final T value, final Duration duration) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        bucket.set(value);
        bucket.expire(duration);
    }

    /**
     * 获取缓存的基本对象
     * @param key 缓存键值
     * @return
     */
    public <T> T getCacheObject(final String key) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        return bucket.get();
    }

    /**
     * 获取缓存的基本对象剩余时间
     * @param key
     * @param <T>
     * @return 剩余时间（单位：毫秒）
     */
    public <T> long getCacheObjectExpire(final String key) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        return bucket.remainTimeToLive() == -2 ? 0L : bucket.remainTimeToLive();
    }

    /**
     * 删除缓存的基本对象
     * @param key 缓存的键值
     * @return
     */
    public <T> boolean deleteCacheObject(final String key) {
        RBucket<T> bucket = redissonClient.getBucket(key);
        return bucket.delete();
    }

    /**
     * 删除所有缓存的基本对象
     * @param pattern 缓存的键值正则表达式
     */
    public <T> void deleteCacheObjectAll(final String pattern) {
        Iterable<String> keysByPattern = getKeys(pattern);
        for (String key : keysByPattern) {
            RBucket<T> bucket = redissonClient.getBucket(key);
            bucket.delete();
        }
    }

    // ============================================== list =============================================================
    /**
     * 缓存List数据（注意是addAll，一直往list中存放数据）
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @return
     */
    public <T> boolean setCacheList(final String key, final List<T> dataList) {
        RList<T> list = redissonClient.getList(key);
        return list.addAll(dataList);
    }

    /**
     * 缓存List数据（注意是addAll，一直往list中存放数据）
     * @param key 缓存的键值
     * @param dataList 待缓存的List数据
     * @param duration 有效时间
     * @return
     */
    public <T> boolean setCacheList(final String key, final List<T> dataList, final Duration duration) {
        RList<T> list = redissonClient.getList(key);
        boolean b = list.addAll(dataList);
        boolean expire = list.expire(duration);
        return b && expire;
    }

    /**
     * 获取缓存的List数据
     * @param key 缓存的键值
     * @return
     */
    public <T> List<T> getCacheList(final String key) {
        RList<T> list = redissonClient.getList(key);
        return list.readAll();
    }

    /**
     * 删除缓存的List数据
     * @param key 缓存的键值
     * @return
     */
    public <T> boolean deleteCacheList(final String key) {
        RList<T> list = redissonClient.getList(key);
        return list.delete();
    }

    /**
     * 删除所有缓存的List数据
     * @param pattern 缓存的键值正则表达式
     * @return
     */
    public <T> void deleteCacheListAll(final String pattern) {
        Iterable<String> keysByPattern = getKeys(pattern);
        for (String key : keysByPattern) {
            RList<T> list = redissonClient.getList(key);
            list.delete();
        }
    }

    // ============================================== hash =============================================================
    /**
     * 缓存Map数据（注意是putAll，一直往map中存放数据）
     * @param key 缓存的键值
     * @param dataMap 待缓存的Map数据
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        RMap<String, T> map = redissonClient.getMap(key);
        map.putAll(dataMap);
    }

    /**
     * 缓存Map数据（注意是putAll，一直往map中存放数据）
     * @param key 缓存的键值
     * @param dataMap 待缓存的Map数据
     * @param duration 有效时间
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap, final Duration duration) {
        RMap<String, T> map = redissonClient.getMap(key);
        map.putAll(dataMap);
        map.expire(duration);
    }

    /**
     * 获取缓存的Map数据
     * @param key 缓存的键值
     * @return
     */
    public <T> Map<String, T> getCacheMap(final String key) {
        RMap<String, T> map = redissonClient.getMap(key);
        return map.readAllMap();
    }

    /**
     * 删除缓存的Map数据
     * @param key 缓存的键值
     * @return
     */
    public <T> boolean deleteCacheMap(final String key) {
        RMap<String, T> map = redissonClient.getMap(key);
        return map.delete();
    }

    // ============================================== set ==============================================================
    /**
     * 缓存Set数据（注意是addAll，一直往set中存放数据）
     * @param key 缓存的键值
     * @param dataSet 待缓存的Set数据
     * @return
     */
    public <T> boolean setCacheSet(final String key, final Set<T> dataSet) {
        RSet<T> set = redissonClient.getSet(key);
        return set.addAll(dataSet);
    }

    /**
     * 缓存Set数据（注意是addAll，一直往set中存放数据）
     * @param key 缓存的键值
     * @param dataSet 待缓存的Set数据
     * @param duration 有效时间
     * @return
     */
    public <T> boolean setCacheSet(final String key, final Set<T> dataSet, final Duration duration) {
        RSet<T> set = redissonClient.getSet(key);
        boolean b = set.addAll(dataSet);
        boolean expire = set.expire(duration);
        return b && expire;
    }

    /**
     * 获取缓存的Set数据
     * @param key 缓存的键值
     * @return
     */
    public <T> Set<T> getCacheSet(final String key) {
        RSet<T> set = redissonClient.getSet(key);
        return set.readAll();
    }

    /**
     * 删除缓存的Set数据
     * @param key 缓存的键值
     * @return
     */
    public <T> boolean deleteCacheSet(final String key) {
        RSet<T> set = redissonClient.getSet(key);
        return set.delete();
    }

    // ============================================== zset =============================================================
    /**
     * 缓存ZSet数据（注意是addAll，一直往ZSet中存放数据）
     * @param key 缓存的键值
     * @param dataZSet 待缓存的ZSet数据
     * @return
     */
    public <T> boolean setCacheZSet(final String key, final Map<T, Double> dataZSet) {
        RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        return scoredSortedSet.addAll(dataZSet) > 0;
    }

    /**
     * 缓存ZSet数据（注意是addAll，一直往ZSet中存放数据）
     * @param key 缓存的键值
     * @param dataZSet 待缓存的ZSet数据
     * @param duration 有效时间
     * @return
     */
    public <T> boolean setCacheZSet(final String key, final Map<T, Double> dataZSet, final Duration duration) {
        RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        int i = scoredSortedSet.addAll(dataZSet);
        boolean expire = scoredSortedSet.expire(duration);
        return i > 0 && expire;
    }

    /**
     * 获取缓存的ZSet分数
     * @param key 缓存的键值
     * @param t 元素
     * @return
     */
    public <T> Double getCacheZSetScore(final String key, final T t) {
        RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        return scoredSortedSet.getScore(t);
    }

    /**
     * 获取缓存的ZSet排名
     * @param key 缓存的键值
     * @param t 元素
     * @return
     */
    public <T> Integer getCacheZSetRank(final String key, final T t) {
        RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        return scoredSortedSet.revRank(t) + 1;
    }

    /**
     * 获取缓存的ZSet指定排名范围
     * @param key 缓存的键值
     * @param start 起始排名（从1开始）
     * @param end 结束排名（从1开始）
     * @return
     */
    public <T> Collection<ScoredEntry<T>> getCacheZSetRange(final String key, final int start, final int end) {
        RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        return scoredSortedSet.entryRangeReversed(start - 1, end == -1 ? end : end - 1);
    }

    /**
     * 删除缓存的ZSet数据
     * @param key 缓存的键值
     * @return
     */
    public <T> boolean deleteCacheZSet(final String key) {
        RScoredSortedSet<T> scoredSortedSet = redissonClient.getScoredSortedSet(key);
        return scoredSortedSet.delete();
    }

    // ============================================== Lua ==============================================================

    /**
     * 运行lua脚本
     * @param luaScript
     * @param keys
     * @param values
     * @return
     */
    public Long executeScript(String luaScript, List<Object> keys, Object... values) {
        RScript script = redissonClient.getScript(StringCodec.INSTANCE);
        String lua = script.scriptLoad(luaScript);
        return script.evalSha(RScript.Mode.READ_WRITE, lua, RScript.ReturnType.INTEGER, keys, values);
    }

    /**
     * 正则匹配所有key
     * @param pattern 缓存的键值正则表达式
     * @return
     */
    private Iterable<String> getKeys(final String pattern) {
        RKeys keys = redissonClient.getKeys();
        return keys.getKeys(new KeysScanParams().pattern(pattern));
    }

}
