package com.jeequan.jeepay.core.cache;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.jeequan.jeepay.core.utils.SpringBeansUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
* Redis工具类
*
* @author terrfly
* @date 2021/5/24 17:58
*/
public class RedisUtil {

    private static StringRedisTemplate stringRedisTemplate = null;

    /** 作用：不同系统的前缀。  a.当连接不同的database时可以为空(物理隔离)； b.当redis集群时因为必须同一个database，所以需通过前缀区分不同系统的业务。 **/
    public static String SYS_PREFIX_KEY = "";

    /** 获取redis 中存入的真实KEY  **/
    public static String getRealKey(String bizKey){
        return (SYS_PREFIX_KEY == null ? "" : SYS_PREFIX_KEY) + bizKey;
    }

    /** 获取redis 中存入的真实KEY : 转换为业务KEY  **/
    public static String getBizKey(String realKey){

        // 前缀说明相同， 无需转换，  参数为空也无需转换
        if(StringUtils.isAnyEmpty(realKey, SYS_PREFIX_KEY)){
            return realKey;
        }

        // 不是相同的前缀
        if(!realKey.startsWith(SYS_PREFIX_KEY)){
            return realKey;
        }

        // 去掉前缀 就是真实的 业务key
        return realKey.substring(SYS_PREFIX_KEY.length());
    }

    /** 获取RedisTemplate对象, 默认使用 StringRedisTemplate, 客户端可查询 **/
    public static StringRedisTemplate getStringRedisTemplate(){

        if(stringRedisTemplate == null){

            if(SpringBeansUtil.getApplicationContext().containsBean("defaultStringRedisTemplate")){
                stringRedisTemplate = SpringBeansUtil.getBean("defaultStringRedisTemplate", StringRedisTemplate.class);
            }else{
                stringRedisTemplate = SpringBeansUtil.getBean(StringRedisTemplate.class);
            }
        }
        return stringRedisTemplate;
    }

    /** 获取缓存数据, String类型 */
    public static String getString(String key) {
        if(key == null) {
            return null;
        }
        return  (String)getStringRedisTemplate().opsForValue().get(RedisUtil.getRealKey(key));
    }

    /** 获取缓存数据对象 */
    public static <T> T getObject(String key, Class<T> cls) {

        String val = getString(key);
        return JSON.parseObject(val, cls);
    }

    /** 放置缓存对象 */
    public static void setString(String key, String value) {
        getStringRedisTemplate().opsForValue().set(RedisUtil.getRealKey(key), value);
    }

    /** 普通缓存放入并设置时间, 默认单位：秒 */
    public static void setString(String key, String value, long time) {
        getStringRedisTemplate().opsForValue().set(RedisUtil.getRealKey(key), value, time, TimeUnit.SECONDS);
    }

    /** 普通缓存放入并设置时间 */
    public static void setString(String key, String value, long time, TimeUnit timeUnit) {
        getStringRedisTemplate().opsForValue().set(RedisUtil.getRealKey(key), value, time, timeUnit);
    }

    /** 放置缓存对象 */
    public static void set(String key, Object value) {
        setString(key, JSON.toJSONString(value));
    }

    /** 普通缓存放入并设置时间, 默认单位：秒 */
    public static void set(String key, Object value, long time) {
        setString(key, JSON.toJSONString(value), time);
    }

    /** 普通缓存放入并设置时间 */
    public static void set(String key, Object value, long time, TimeUnit timeUnit) {
        setString(key, JSON.toJSONString(value), time, timeUnit);
    }

    /** 指定缓存失效时间 */
    public static void expire(String key, long time) {
       getStringRedisTemplate().expire(RedisUtil.getRealKey(key), time, TimeUnit.SECONDS);
    }

    /** 指定缓存失效时间 */
    public static void expire(String key, long time, TimeUnit timeUnit) {
        getStringRedisTemplate().expire(RedisUtil.getRealKey(key), time, timeUnit);
    }

    /**
     * 根据key 获取过期时间
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public static long getExpire(String key) {
        return getStringRedisTemplate().getExpire(RedisUtil.getRealKey(key), TimeUnit.SECONDS);
    }

    /** 判断key是否存在 */
    public static boolean hasKey(String key) {
        return getStringRedisTemplate().hasKey(RedisUtil.getRealKey(key));
    }

    /** 删除缓存，根据key **/
    public static void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                getStringRedisTemplate().delete(RedisUtil.getRealKey(key[0]));
            } else {

                List<String> realKeys = new ArrayList<>();
                for (String s : key) {
                    realKeys.add(RedisUtil.getRealKey(s));
                }

                getStringRedisTemplate().delete(realKeys);
            }
        }
    }

    /** 删除缓存，根据key前缀 **/
    public static void delByPrefix(String keyPrefix) {
        StringRedisTemplate redisTemplate = getStringRedisTemplate();

        Set<String> keys = redisTemplate.keys(getRealKey(keyPrefix) + "*");
        if (CollUtil.isEmpty(keys)) {
            return;
        }

        for (String key : keys) {
            redisTemplate.delete(key);
        }
    }

    /** 查询keys */
    public static Collection<String> keys(String pattern) {

        Collection<String> queryResult = getStringRedisTemplate().keys(RedisUtil.getRealKey(pattern));
        if(queryResult == null || queryResult.isEmpty()){
            return queryResult;
        }

        // 转换为： 业务的key
        Collection<String> result = new ArrayList<>();
        for (String s : queryResult) {
            result.add(RedisUtil.getBizKey(s));
        }

        return result;
    }

    /** 获取缓存数据, String类型 */
    public static Long increment(String key, long delta) {
        if(key == null) {
            return null;
        }
        return getStringRedisTemplate().opsForValue().increment(RedisUtil.getRealKey(key), delta);
    }

}
