package com.bohuikeji.frame.module.admin.component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.bohuikeji.frame.module.admin.utils.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 * @author 10552
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class RedisUtil {
    private final RedisTemplate<String, Object> redisTemplate;

    @Value("${tools.queue-pix}")
    private String evn;


    /**
     * 获取key
     * 避免生产环境和测试环境数据混淆
     * @param key
     * @return
     */
    private String getKey(String key){
        return evn+":"+key;
    }
    private String[] getKeys(String... keys){
        for (int i=0;i<keys.length;i++) {
            keys[i]=evn+":"+keys[i];
        }
        return keys;
    }

    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    private boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        long time=-1;
        try {
            time=redisTemplate.getExpire(getKey(key), TimeUnit.SECONDS);
        }catch (Exception e){
            log.error("获取KEY={}过期时间失败！",get(key));
        }
        return time;
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(getKey(key));
        } catch (Exception e) {
            log.error("【Redis异常】判断key存在失败",e);
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    @SuppressWarnings("unchecked")
    public void del(String... key) {
        redisTemplate.delete(Arrays.asList(getKeys(key)));
    }

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(getKey(key));
    }

    /**
     * 获取指定对象的缓存
     * @param key
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> T get(String key,Class<T> tClass){
        return getByFinalKey(getKey(key),tClass);
    }

    /**
     * 使用最终KEY查询，不对key做额外的环境处理
     * @param key
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> T getByFinalKey(String key,Class<T> tClass){
        Object cache=key == null ? null :redisTemplate.opsForValue().get(key);
        return cache==null?null:JSON.parseObject(cache.toString(),tClass);
    }
    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public  <T> List<T> getList(String key,Class<T> tClass) {
        Object cache=key == null ? new ArrayList<T>(0) :redisTemplate.opsForValue().get(getKey(key));
        return cache == null ? new ArrayList<T>(0) :JSON.parseArray(cache.toString(),tClass);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    private boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        key=getKey(key);
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 插入list
     * @param key
     * @param listValue
     * @param time
     * @return
     */
    public boolean setList(String key,List listValue, long time){
        key=getKey(key);
        try{
            redisTemplate.opsForList().rightPushAll(key,listValue);
            if(time>0){
                expire(key,time);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 插入一条数据到list
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean pushList(String key,Object value, long time){
        key=getKey(key);
        try{
            redisTemplate.opsForList().rightPush(key,value);
            if(time>0){
                expire(key,time);
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 获取list大小
     * @param key
     * @return
     */
    public Long listSize(String key) {
        return redisTemplate.opsForList().size(getKey(key));
    }

    /**
     * 按区间查询list
     * @param key
     * @param start
     * @param end
     * @return
     */
    public  <T> List<T> getListByRang(String key,long start,long end,Class<T> tClass){
        return JSON.parseArray(JSON.toJSONString(redisTemplate.opsForList().range(getKey(key),start,end)),tClass);
    }

    /**
     * 模糊查询一组数据
     * @param pattern
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> List<T> getListByPattern(String pattern,Class<T> tClass){
        List<T> list=new ArrayList<>();
        scan(getKey(pattern)).forEach(key->{
            list.add(getByFinalKey(key,tClass));
        });
        return list;
    }

    /**
     * 模糊查询key
     * @param pattern 匹配表达式
     * @return 返回key集合
     */
    public Set<String> getPatternKeys(String pattern){
        return scan(getKey(pattern));
    }

    /**
     * 执行Redis Scan命令
     * @param pattern
     * @return
     */
    public  Set<String> scan(String pattern) {
        return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keysTmp = new HashSet<>();
            try (Cursor<byte[]> cursor = connection.scan(ScanOptions.scanOptions()
                    .match(pattern)
                    .count(10000).build())) {
                while (cursor.hasNext()) {
                    keysTmp.add(new String(cursor.next(), "Utf-8"));
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new RuntimeException(e);
            }
            return keysTmp;
        });
    }

}
