package com.zanxiang.game.data.serve.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author : lingfeng
 * @time : 2021-11-23
 * @description : redis缓存通用前缀
 */
@Component
@Slf4j
public class RedisUtil<T> {

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 设置缓存
     *
     * @param key  : 缓存key
     * @param t    : 缓存对象
     * @param time : 过期时间
     * @return : 返回是否设置成功
     */
    public boolean setCache(String key, T t, long time) {
        try {
            ValueOperations<String, T> operations = redisTemplate.opsForValue();
            operations.set(key, t, time, TimeUnit.SECONDS);
            return true;
        } catch (Exception e) {
            log.error("缓存添加异常, key : {}, value : {}, e : {}", key, t, e.getMessage());
        }
        return false;
    }

    /**
     * 获取缓存方法
     *
     * @param key : 缓存key
     * @return : 返回缓存对象
     */
    public T getCache(String key) {
        try {
            if (redisTemplate.hasKey(key)) {
                ValueOperations<String, T> operations = redisTemplate.opsForValue();
                return operations.get(key);
            }
        } catch (Exception e) {
            log.error("获取缓存异常, key : {}, e : {}", key, e.getMessage());
        }
        return null;
    }

    /**
     * redis 事物锁设置方法
     *
     * @param key  : 缓存key
     * @param t    : 缓存对象
     * @param time : 过期时间
     * @return : 返回是否设置成功
     */
    public boolean setIfAbsent(String key, T t, long time) {
        try {
            ValueOperations<String, T> operations = redisTemplate.opsForValue();
            return operations.setIfAbsent(key, t, time, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("缓存添加异常, key : {}, value : {}, e : {}", key, t, e.getMessage());
        }
        return false;
    }

    /**
     * 删除缓存的方法
     *
     * @param key : 缓存key
     * @return : 返回缓存对象
     */
    public boolean deleteCache(String key) {
        try {
            if (redisTemplate.hasKey(key)) {
                return redisTemplate.delete(key);
            }
        } catch (Exception e) {
            log.error("删除缓存异常, key : {}, e : {}", key, e.getMessage());
        }
        return false;
    }

    /**
     * set集合添加元素
     *
     * @param key : 缓存key
     * @param t   : 需要添加的元素
     * @return : 返回是否添加成功
     */
    public boolean addToSet(String key, T... t) {
        try {
            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
            Long add = setOperations.add(key, t);
            return add != null && add >= 1;
        } catch (Exception e) {
            log.error("Set添加失败,key : {}, e : {}", key, e.getMessage());
        }
        return false;
    }

    /**
     * set集合删除元素
     *
     * @param key : 缓存key
     * @param t   : 需要删除的元素
     * @return : 返回是否删除成功
     */
    public boolean removeOfSet(String key, T... t) {
        try {
            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
            Long remove = setOperations.remove(key, t);
            return remove != null && remove >= 1;
        } catch (Exception e) {
            log.error("Set删除失败,key : {}, e : {}", key, e.getMessage());
        }
        return false;
    }

    /**
     * 判断元素是否存在于set集合
     *
     * @param key : 缓存key
     * @param t   : 需要判断的元素
     * @return : 判断元素是否存在
     */
    public boolean isMemberInSet(String key, T t) {
        try {
            SetOperations<String, T> setOperations = redisTemplate.opsForSet();
            return setOperations.isMember(key, t);
        } catch (Exception e) {
            log.error("Set元素是否存在判断异常, key : {}, e : {}", key, e.getMessage());
        }
        return false;
    }

    /**
     * 添加单个缓存到list
     *
     * @param key   : 缓存key
     * @param t     : 缓存元素
     * @param isTop : isTop :  真:前 假:后
     * @return : 返回添加结果
     */
    public boolean setListCache(String key, T t, boolean isTop) {
        try {
            ListOperations<String, T> listOperations = redisTemplate.opsForList();
            if (isTop) {
                listOperations.leftPush(key, t);
            } else {
                listOperations.rightPush(key, t);
            }
            return true;
        } catch (Exception e) {
            log.error("redis添加队列元素失败,key : {}, e : {}", key, e.getMessage());
        }
        return false;
    }

    /**
     * 获取列表中的前or后的值
     *
     * @param key   : 缓存key
     * @param isTop :  真:前 假:后
     * @return : 返回缓存数据
     */
    public T getListOneCache(String key, boolean isTop) {
        try {
            if (redisTemplate.hasKey(key)) {
                ListOperations<String, T> listOperations = redisTemplate.opsForList();
                T t = null;
                if (isTop) {
                    t = listOperations.leftPop(key);
                } else {
                    t = listOperations.rightPop(key);
                }
                return t;
            }

        } catch (Exception e) {
            log.error("redis获取队列元素失败,key : {}, e : {}", key, e.getMessage());
        }
        return null;
    }

    /**
     * 添加单个元素进入有序集合
     *
     * @param key   : 缓存key
     * @param t     : 缓存值
     * @param score : 分数
     * @return : 返回是否添加成功
     */
    public boolean addZSet(String key, T t, double score) {
        try {
            ZSetOperations zSet = redisTemplate.opsForZSet();
            Boolean add = zSet.add(key, t, score);
            return add == null ? false : add;
        } catch (Exception e) {
            log.error("ZSet添加失败元素失败, key : {}, t : {}, score : {}, e : {}", key, t.toString(), score, e.getMessage());
        }
        return false;
    }

    /**
     * 获取分数区间
     *
     * @param key : 缓存key
     * @param min : 最小值
     * @param max : 最大值
     * @return {@link Set}<{@link T}>
     */
    public Set<T> getZSetByScore(String key, Double min, Double max) {
        try {
            ZSetOperations<String, T> zSet = redisTemplate.opsForZSet();
            Set<T> set = zSet.rangeByScore(key, min, max);
            return set;
        } catch (Exception e) {
            log.error("ZSet获取元素失败, key : {}, min : {}, max : {}, e : {}", key, min, max, e.getMessage());
        }
        return null;
    }


    /**
     * 按照索引区间获取(按分数正序排序)
     * (0, -1)表示获取全部
     *
     * @param key   : 缓存key
     * @param start : 开始
     * @param end   : 结束
     * @return {@link Set}<{@link T}>
     */
    public Set<T> rangeZSet(String key, long start, long end) {
        try {
            ZSetOperations<String, T> zSet = redisTemplate.opsForZSet();
            return zSet.range(key, start, end);
        } catch (Exception e) {
            log.error("ZSet获取元素失败, key : {}, start : {}, end : {}, e : {}", key, start, end, e.getMessage());
        }
        return null;
    }

    /**
     * 按照缓存值删除
     *
     * @param key : 缓存key
     * @param t   : 缓存值
     * @return boolean : 删除结果
     */
    public boolean delZSetValue(String key, T t) {
        try {
            ZSetOperations<String, T> zSet = redisTemplate.opsForZSet();
            Long remove = zSet.remove(key, t);
            return remove != null && remove == 1;
        } catch (Exception e) {
            log.error("ZSet删除元素失败, key : {}, t : {}, , e : {}", key, t, e.getMessage());
        }
        return false;
    }
}
