package com.zzsn.cache;

import com.zzsn.util.Constants;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.List;
import java.util.Set;

public class JedisUtil {

    private static final String PREFIX = "weixin_";
    private static final Logger logger = LoggerFactory.getLogger(JedisUtil.class);
    private static JedisPool jedisPool = null;

    private JedisUtil() {

    }

    /**
     * 从jedis连接池中获取获取jedis对象
     *
     * @return
     */
    private static void init(){
        String host = Constants.REDIS_LOCALHOST;
        String port = Constants.REDIS_PORT;
        String pass = Constants.REDIS_PASS;
        String timeout = Constants.REDIS_TIMEOUT;
        String maxIdle = Constants.REDIS_MAXIDLE;
        String maxTotal = Constants.REDIS_MAXTOTAL;
        String maxWaitMillis = Constants.REDIS_MAXWAITMILLIS;
        String testOnBorrow = Constants.REDIS_TESTONBORROW;

        JedisPoolConfig config = new JedisPoolConfig();
        //控制一个pool可分配多少个jedis实例，通过pool.getResource()来获取；
        //如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
        config.setMaxTotal(Integer.parseInt(maxTotal));
        //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
        config.setMaxIdle(Integer.parseInt(maxIdle));
        //表示当borrow(引入)一个jedis实例时，最大的等待时间，如果超过等待时间，则直接抛出JedisConnectionException；
        config.setMaxWaitMillis(Long.parseLong(maxWaitMillis));
        //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
        config.setTestOnBorrow(Boolean.valueOf(testOnBorrow));
        jedisPool = new JedisPool(config, host, Integer.parseInt(port), Integer.parseInt(timeout));
    }
    private static Jedis getJedis() {
        init();
        return jedisPool.getResource();
    }

    private static final JedisUtil jedisUtil = new JedisUtil();

    /**
     * 获取JedisUtil实例
     *
     * @return
     */
    public static JedisUtil getInstance() {
        return jedisUtil;
    }

    public static void returnResource(final Jedis jedis) {
        if (jedis != null && jedisPool != null) {
            jedis.close();
        }
    }
    public static Jedis getDefaultJedis() {
        // return getJedis(HOST_IP, HOST_PORT);//简装版

        return getJedis();
    }
    /**
     * 根据 pattern 获取 redis 中的键
     */
    public static Set<String> getKeysByPattern(String pattern) {
        return getDefaultJedis().keys(pattern);
    }

    public static boolean exists(String key) throws Exception {

        if (StringUtils.isEmpty(key)) {
            throw new Exception("key is null");
        }

        return getDefaultJedis().exists(PREFIX + key);
    }

    public static void del(String key) throws Exception {
        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }
        Jedis jedis=null;
        try {
            jedis = getDefaultJedis();
            jedis.del(PREFIX + key);
        }catch (Exception e){

        }finally {
            returnResource(jedis);
        }
    }

    public static void setString(String key, String value, int expireTime) throws Exception {
        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }

        String finalKey = PREFIX + key;
        Jedis jedis=null;
        try {
            jedis = getDefaultJedis();
            jedis.set(finalKey, value);
            if (expireTime > 0) {
                /**
                 * 如果设置了 expireTime， 那么这个 finalKey会在expireTime秒后过期,那么该键会被自动删除
                 * 这一功能配合出色的性能让Redis可以作为缓存系统来使用，成为了缓存系统Memcached的有力竞争者
                 */
                jedis.expire(finalKey, expireTime);
            } else {
                jedis.expire(finalKey, 60 * 60 * 24 * 15);
            }
        }catch (Exception e){

        }finally {
            returnResource(jedis);
        }
    }

    public static String getString(String key) throws Exception {
        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }
        Jedis jedis=null;
        String value="";
        try {
            jedis = getDefaultJedis();
            value = jedis.get(PREFIX + key);
        }catch (Exception e){

        }finally {
            returnResource(jedis);
        }
        return value;
    }

    public static long setnx(String key, String value) throws Exception {

        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }

        return getDefaultJedis().setnx(PREFIX + key, value);
    }
    public static long expire(String key, int seconds) throws Exception {

        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }

        return getDefaultJedis().expire(PREFIX + key, seconds);
    }
    public static void pushList(String key, String value, String flag) throws Exception {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(flag)) {
            logger.error("key or flag is null");
            throw new Exception("key or flag is null");
        }

        /**
         * key代表的是链表的名字 List是一个双端链表，lpush是往链表的头部插入一条数据，rpush是往尾部插入一条数据
         */
        if (flag.equalsIgnoreCase("L")) {
            getDefaultJedis().lpush(PREFIX + key, value);
        } else if (flag.equalsIgnoreCase("R")) {
            getDefaultJedis().rpush(PREFIX + key, value);
        } else {
            logger.error("unknown flag");
            throw new Exception("unknown flag");
        }
    }

    public static String popList(String key, String flag) throws Exception {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(flag)) {
            logger.error("key or flag is null");
            throw new Exception("key or flag is null");
        }

        if (flag.equalsIgnoreCase("L")) {
            return getDefaultJedis().lpop(PREFIX + key);
        } else if (flag.equalsIgnoreCase("R")) {
            return getDefaultJedis().rpop(PREFIX + key);
        } else {
            logger.error("unknown flag");
            throw new Exception("unknown flag");
        }
    }
    /**
     * 获取 List 中指定区间上的元素
     */
    public static List<String> getAppointedList(String key, long start, long end) throws Exception {
        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }
        return getDefaultJedis().lrange(PREFIX + key, start, end);
    }
    public static List<String> getList(String key) throws Exception {
        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }
        return getDefaultJedis().lrange(PREFIX + key, 0, -1);
    }

    public static void sadd(String key,String value)throws Exception{

        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }
        getDefaultJedis().sadd(key,value);
    }
    public static boolean sismember(String key,String value)throws Exception{
        if (StringUtils.isEmpty(key)) {
            logger.error("key is null");
            throw new Exception("key is null");
        }
        return getDefaultJedis().sismember(key,value);
    }
}
