package com.gyee.wisdom.it235.util;


import com.alibaba.fastjson.JSONObject;
import com.gyee.wisdom.common.utils.ByteUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.data.redis.connection.RedisConnection;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * @description: 单值/对象操作
 * @author: jianjun.ren
 * @date: Created in 2020/9/27 11:45
 */
@ConditionalOnBean(RedisBaseUtil.class)
//@Component
public class RedisValUtil extends RedisBaseUtil {

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

    /**
     * 获取 String 类型 key-value
     *
     * @param key 键
     * @return
     */
    public String get(String key) {
        return get(defaultDB ,key);
    }
    public String get(int dbIndex ,String key) {
        Object result = knife4jRedisManager.redisTemplate(dbIndex).opsForValue().get(key);
        return result == null ? null : result.toString();
    }

    public byte[] getBytes(int dbIndex, String key) {
        try {
            byte[] bkey = key.getBytes("ascii");
            return (byte[]) knife4jRedisManager.redisTemplate(dbIndex).execute((RedisConnection redisConnection) ->redisConnection.get(bkey));
        } catch (Exception e) {}

        return null;

    }

    public List<byte[]> getBytesList(int dbIndex,List<String> keyList){
        List<byte[]> resultList=new ArrayList<>();
        try {
            byte[][] rawKeys = new byte[keyList.size()][];
            for (int i = 0; i < keyList.size(); i++) {
                rawKeys[i]=keyList.get(i).getBytes("ascii");
            }

            resultList = knife4jRedisManager.redisTemplate(dbIndex).getConnectionFactory().getConnection().mGet(rawKeys);
        }catch (Exception ex){

        }finally {
            return resultList;
        }
    }

    //将数据转化为二进制进行存储
    public boolean setBytesList(int dbIndex,List<String> keyList) throws UnsupportedEncodingException {
        Map<byte[], byte[]> b = new HashMap<>();
            byte[][] rawKeys = new byte[keyList.size()][];
            double min = 1.0;
            double max = 10.0;
            for (int i = 0; i < keyList.size(); i++) {
                rawKeys[i] = keyList.get(i).getBytes("ascii");
                byte[] bb = {};
                //随机生成double
                double generatedDouble = ThreadLocalRandom.current().nextDouble(min, max);
                byte[] bt1 = ByteUtil.putDouble(bb, generatedDouble, 0);
                long time = new Date().getTime();
                byte[] bt2 = ByteUtil.putLong(bb, time, 0);
                byte[] bt3 = new byte[bt1.length+bt2.length];
                bt3[0] = bt1[0];
                bt3[1] = bt1[1];
                bt3[2] = bt1[2];
                bt3[3] = bt1[3];
                bt3[4] = bt1[4];
                bt3[5] = bt1[5];
                bt3[6] = bt1[6];
                bt3[7] = bt1[7];
                bt3[8] = bt2[0];
                bt3[9] = bt2[1];
                bt3[10] = bt2[2];
                bt3[11] = bt2[3];
                bt3[12] = bt2[4];
                bt3[13] = bt2[5];
                bt3[14] = bt2[6];
                bt3[15] = bt2[7];
                b.put(rawKeys[i], bt3);
            }
           return knife4jRedisManager.redisTemplate(2).getConnectionFactory().getConnection().mSet(b);
    }

    /**
     * 获取单对象 redis<String,Clazz>
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public <T> T get(String key , Class<T> clazz) {
        return  get(defaultDB ,key , clazz);
    }
    public <T> T get(int dbIndex ,String key , Class<T> clazz) {
        Object o = knife4jRedisManager.redisTemplate(dbIndex).opsForValue().get(key);
        if(o instanceof JSONObject){
            JSONObject jo = (JSONObject)o;
            T t = jo.toJavaObject(clazz);
            return t;
        }
        T t = JSONObject.parseObject(JSONObject.toJSONString(o), clazz);
        return t;
    }

    /**
     * 带失效时间设置
     *
     * @param key     键
     * @param value   值
     * @param timeout 失效时间（秒）
     */
    public void set(String key, Object value, long timeout) {
        set(defaultDB , key ,value ,timeout);
    }
    public void set(int dbIndex ,String key, Object value, long timeout) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
    }

    /**
     * 为多个键分别设置他们的值
     * 使用：Map<String,String> maps = new HashMap<String, String>();
     * maps.put("multi1","ccc");
     * maps.put("multi2","xxx");
     * maps.put("multi3","zzz");
     * template.opsForValue().multiSet(maps);
     *
     * @param map
     */
    protected void multiSetObj(Map<String, Object> map) {
        multiSetObj(defaultDB , map);
    }
    protected void multiSetObj(int dbIndex ,Map<String, Object> map) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForValue().multiSet(map);
    }

    /***
     * 分多个键同时取出他们的值
     * List<String> keys = new ArrayList<String>();
     keys.add("multi1");
     keys.add("multi2");
     keys.add("multi3");
     System.out.println(template.opsForValue().multiGet(keys));
     结果：[ccc, xxx, zzz]
     * @param keys
     *
     */
    protected List<Object> multiGetObj(List<String> keys) {
        return multiGetObj(defaultDB ,keys);
    }
    public List<Object> multiGetObj(int dbIndex ,List<String> keys) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().multiGet(keys);
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        return incr(defaultDB , key , delta);
    }
    public long incr(int dbIndex ,String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().increment(key, delta);
    }

    public long incrFiled(String key, String filed) {
        return incrFiled(defaultDB , key , filed);
    }
    public long incrFiled(int dbIndex ,String key, String filed) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForHash().increment(key, filed, 1);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        return decr(defaultDB , key ,delta);
    }
    public long decr(int dbIndex ,String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().increment(key, -delta);
    }

    //存hash
    public void setHash(String key, String filed, String value) {
        setHash(defaultDB ,key , filed ,value);
    }
    public void setHash(int dbIndex ,String key, String filed, String value) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForHash().put(key, filed, value);
    }

    //取hash
    public String getHash(String key, String filed) {
        return getHash(defaultDB ,key ,filed);
    }
    public String getHash(int dbIndex ,String key, String filed) {
        Object o = knife4jRedisManager.redisTemplate(dbIndex).opsForHash().get(key, filed);
        return (String) o;
    }

    public void setList(String key, List<String> list) {
        setList(defaultDB , key , list);
    }
    public void setList(int dbIndex ,String key, List<String> list) {
        knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPush(key, list);
    }

    public List<String> getList(String key) {
        return getList(defaultDB ,key);
    }
    public List<String> getList(int dbIndex ,String key) {
        return (List<String>) knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPop(key);
    }

    public void lPush(String key, String value){
        lPush(defaultDB , key , value);
    }
    public void lPush(int dbIndex ,String key, String value){
        knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPush(key, value);
    }

    public String lPop(String key){
        return lPop(defaultDB ,key);
    }
    public String lPop(int dbIndex ,String key){
        return (String) knife4jRedisManager.redisTemplate(dbIndex).opsForList().leftPop(key);
    }

    public Long listSize(String key){
        return listSize(defaultDB , key);
    }
    public Long listSize(int dbIndex ,String key){
        return knife4jRedisManager.redisTemplate(dbIndex).opsForList().size(key);
    }



    //查询list中指定范围的内容
    public List<String> range(String key){
        return range(defaultDB , key);
    }
    public List<String> range(int dbIndex ,String key){
        List<Object> range = knife4jRedisManager.redisTemplate(dbIndex).opsForList().range(key, 0, -1);
        List<String> result = new ArrayList<>();
        for (Object o : range) {
            result.add((String)o);
        }
        return result;
    }

    public Long ttl(String key) {
        return ttl(defaultDB , key);
    }
    public Long ttl(int dbIndex ,String key) {
        return knife4jRedisManager.redisTemplate(dbIndex).opsForValue().getOperations().getExpire(key);
    }
}