package com.sunyard.ssp.redis;

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.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import redis.clients.jedis.BinaryJedisPubSub;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

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

/**
 * @author:tsz
 * @date:2020/3/6
 * @description: 操作任意类型的 Template
 */
@Component
@Slf4j
public class RedisObjectOperation {

    @Autowired
    private RedisTemplate<Object, Object> objectRedisTemplate;
    @Value("${spring.redis.isJq}")
    private Boolean isJq;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.cluster.nodes}")
    private String redisNodes;
    @Autowired
    private JedisCluster jedisCluster;
    @Autowired
    private JedisPool jedisPool;

    /***
     * 操作对象
     */
    public void ObjectSet(Object key, Object value) {
        ValueOperations<Object, Object> valueOperations = objectRedisTemplate.opsForValue();
        valueOperations.set(key, value);
    }

    /***
     * 操作元素为对象列表
     */
    public void ListSet(Object key, List<Object> values) {
        ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
        values.forEach(value -> listOperations.leftPush(key, value));
    }

    /**
     * 对象存储到redis 的list 中
     *
     * @param key
     * @param value
     */
    public void ListSet(Object key, Object value) {
        ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
        listOperations.leftPush(key, value);
    }

    /**
     * 移除list 中的数据
     *
     * @param key
     * @param start
     * @param end
     */
    public void ListTrim(Object key, Long start, Long end) {
        ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
        listOperations.trim(key, start, end);
    }

    /**
     * 获得list 对象
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List<Object> ListGet(Object key, Long start, Long end) {
        ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
        return listOperations.range(key, start, end);
    }


    /***
     * 操作元素为对象集合
     */
    public void SetSet(Object key, Set<Object> values) {
        SetOperations<Object, Object> setOperations = objectRedisTemplate.opsForSet();
        values.forEach(value -> setOperations.add(key, value));
    }

    /***
     * 获取对象
     */
    public Object ObjectGet(Object key) {
        ValueOperations<Object, Object> valueOperations = objectRedisTemplate.opsForValue();
        return valueOperations.get(key);
    }

    /***
     * 列表弹出元素
     */
    public Object ListLeftPop(Object key) {
        ListOperations<Object, Object> listOperations = objectRedisTemplate.opsForList();
        return listOperations.leftPop(key, 2, TimeUnit.SECONDS);
    }

    /***
     * 集合弹出元素
     */
    public Object SetPop(Object key) {
        SetOperations<Object, Object> setOperations = objectRedisTemplate.opsForSet();
        return setOperations.pop(key);
    }


    public void close() {
        if (!isJq) {
            if (null != jedisPool) {
                try {
                    jedisPool.close();
                } catch (Exception e) {
                }
            }
        } else {
            if (null != jedisCluster) {
                try {
                    jedisCluster.close();
                } catch (Exception e) {
                }
            }
            jedisCluster = null;
        }
    }

    public Set<String> keys(String pattern) {

        Set<String> keys = new HashSet<>();
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);

                keys = jedis.keys(pattern);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
                //close();
            }
        } else {
            try {
                //获取所有连接池节点
                //Map<String, JedisPool> nodes = jedisCluster.getClusterNodes();
                String nodes[] = redisNodes.split(",");
                for(String node : nodes){
                    String host = node.split(":")[0];
                    Integer port = Integer.valueOf(node.split(":")[1]);
                    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
                    jedisPoolConfig.setMaxIdle(1000);
                    jedisPoolConfig.setBlockWhenExhausted(false);
                    jedisPoolConfig.setJmxEnabled(true);
                    log.debug("从【{}】获取keys", node);
                    JedisPool pool = new JedisPool(jedisPoolConfig,host,port,10000,password);
                    Jedis jedis = null;
                    try {
                        jedis = pool.getResource();
                        keys.addAll(jedis.keys(pattern));
                    } catch (Exception e) {
                        log.error("获取key异常", e);
                    } finally {
                        log.info("关闭连接");
                        //一定要关闭连接！
                        if (jedis != null) {
                            jedis.close();
                        }
                    }
                }
                //遍历所有连接池，逐个进行模糊查询
                /*for (String k : nodes.keySet()) {
                    log.debug("从【{}】获取keys", k);
                    JedisPool pool = nodes.get(k);
                    //获取Jedis对象，Jedis对象支持keys模糊查询
                    Jedis jedis = null;
                    try {
                        jedis = pool.getResource();
                        keys.addAll(jedis.keys(pattern));
                    } catch (Exception e) {
                        log.error("获取key异常", e);
                    } finally {
                        log.info("关闭连接");
                        //一定要关闭连接！
                        if (jedis != null)
                            jedis.close();
                    }
                }*/
            } catch (Exception e) {
                log.error("获取key异常", e);
            }
        }
        return keys;

    }

    public String get(String pattern) {

        String keys;
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);

                keys = jedis.get(pattern);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
                //close();
            }
        } else {
            keys = jedisCluster.get(pattern);
        }
        return keys;

    }

    public void set(String key, String value) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                jedis.set(key, value);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
                //close();
            }
        } else {
            jedisCluster.set(key, value);
        }


    }

    public void delete(Set<String> keys) {


        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                for (String key : keys) {
                    jedis.del(key);
                }

            } finally {
                if (jedis != null) {
                    jedis.close();
                }
                //close();
            }
        } else {
            for (String key : keys) {
                jedisCluster.del(key);
            }
        }

    }


    public void subscribe(BinaryJedisPubSub jedisPubSub, final byte[]... channels) {


        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);

                jedis.subscribe(jedisPubSub, channels);
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
                //close();
            }
        } else {
            jedisCluster.subscribe(jedisPubSub, channels);
        }

    }

    public Long zrem(final String key, final String... members) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                return jedis.zrem(key, members);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            return jedisCluster.zrem(key, members);
        }
    }

    public Long zremrangeByScore(final byte[] key, final double min, final double max) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                return jedis.zremrangeByScore(key, min, max);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            return jedisCluster.zremrangeByScore(key, min, max);
        }
    }

    public Long zremrangeByScore(final String key, final double min, final double max) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                return jedis.zremrangeByScore(key, min, max);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            return jedisCluster.zremrangeByScore(key, min, max);
        }
    }

    public Set<String> zrangeByScore(String key, double min, double max) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                return jedis.zrangeByScore(key, min, max);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            return jedisCluster.zrangeByScore(key, min, max);
        }
    }

    public Long zadd(final String key, final double score, final String member) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            jedis.auth(password);
            return jedis.zadd(key, score, member);
        } else {
            return jedisCluster.zadd(key, score, member);
        }
    }

    public Long zadd(final byte[] key, final double score, final byte[] member) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            jedis.auth(password);
            return jedis.zadd(key, score, member);
        } else {
            return jedisCluster.zadd(key, score, member);
        }
    }

    public Set<String> zrange(final String key, final long start, final long stop) {


        Set<String> zrange;
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                zrange = jedis.zrange(key, start, stop);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            zrange = jedisCluster.zrange(key, start, stop);

        }
        return zrange;

    }

    public Long sadd(final String key, final String... members) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            jedis.auth(password);
            return jedis.sadd(key, members);
        } else {
            return jedisCluster.sadd(key, members);
        }
    }

    public Long del(final String key) {
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            try {
                jedis.auth(password);
                return jedis.del(key);
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            return jedisCluster.del(key);
        }
    }


    public Long publish(final byte[] channel, final byte[] message) {
        Long publish = null;
        if (!isJq) {
            Jedis jedis = jedisPool.getResource();
            log.info("jedis publish[{}]", jedis);
            try {
                jedis.auth(password);
                publish = jedis.publish(channel, message);

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    jedis.close();
                    //close();
                }
            }
        } else {
            publish = jedisCluster.publish(channel, message);
        }
        return publish;
    }

}
