package com.inkasso.config.cache;

import com.inkasso.factoring.system.Session;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.io.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

@Component
public class RedisCache {

    private static Logger logger = LoggerFactory.getLogger(RedisCache.class);
    private final static int DEFAULT_EXPIRED_SECOND = 60 * 60;
    @Autowired
    @Qualifier("jedisPool")
    private JedisPool jedisPool;
    @Value("${redis.indexDB}")
    private int indexDB;

    private Jedis getRedis() {
        Jedis jedis = jedisPool.getResource();
        jedis.select(indexDB);
        return jedis;
    }

    /**
     * 获取缓存
     */
    public Object get(String key) {
        Jedis jedis = getRedis();
        try {
            if (StringUtils.isNotEmpty(key)) {
                return unserialize(jedis.get(key.getBytes()));
            }
        } catch (Exception e) {
            logger.error("Exception occur when getCached value with key=" + key, e);
        } finally {
            jedis.close();
        }
        return null;
    }

    /**
     * 获取全部缓存session
     *
     * @param startKey
     * @return
     */
    public List<Session> getSession(String startKey) {
        Jedis jedis = getRedis();
        try {
            List<Session> objs = new ArrayList<Session>();
            Set<String> s = jedis.keys(startKey + "*");
            Iterator<String> it = s.iterator();
            while (it.hasNext()) {
                String key = (String) it.next();
                Object value = unserialize(jedis.get(key.getBytes()));
                objs.add((Session) value);
            }
            return objs;
        } catch (Exception e) {
            logger.error("Exception occur when getCached value", e);
        } finally {
            jedis.close();
        }
        return null;
    }

    /**
     * 获取缓存并更新缓存时间
     */
    public Object getAndUpdate(String key, int expried) {
        try {
            Object value = get(key);
            if (value != null) {
                expried = expried > 0 ? expried : DEFAULT_EXPIRED_SECOND;
                set(key, expried, value);
            }
            return value;
        } catch (Exception e) {
            logger.error("Exception occur when getAndUpdateCached value with key=" + key, e);
            return null;
        }
    }

    /**
     * 设置缓存
     */
    public void set(String key, Object value) {
        set(key, DEFAULT_EXPIRED_SECOND, value);
    }

    public void set(String key, int expried, Object value) {
        Jedis jedis = getRedis();
        try {
            if (value != null && StringUtils.isNotEmpty(key)) {
                jedis.setex(key.getBytes(), expried, serialize(value));
            }
        } catch (Exception e) {
            logger.error("Exception occur when setCached value with key=" + key + ",value=" + value, e);
        } finally {
            jedis.close();
        }
    }

    public void remove(String key) {
        Jedis jedis = getRedis();
        try {
            if (StringUtils.isNotEmpty(key)) {
                jedis.del(key);
            }
        } catch (Exception e) {
            logger.error("Exception occur when removeCached value with key=" + key, e);
        } finally {
            jedis.close();
        }
    }

    public Object get(String nameSpace, String key) {
        if (StringUtils.isEmpty(nameSpace) || StringUtils.isEmpty(key)) {
            return null;
        }
        return get(nameSpace + "_" + key);
    }

    public void invalidateNameSpaceCache(String nameSpace) {
        Jedis jedis = getRedis();
        try {
            if (StringUtils.isEmpty(nameSpace)) {
                return;
            }
            Set<byte[]> sets = jedis.keys((nameSpace + "*").getBytes());
            if (sets != null) {
                for (byte[] set : sets) {
                    jedis.del(set);
                }
            }
        } catch (Exception e) {
            logger.error("Exception occur when invalidateNameSpaceCached with nameSpace=" + nameSpace, e);
        } finally {
            jedis.close();
        }
    }

    /**
     * 移除缓存
     */
    public void remove(String nameSpace, String key) {
        if (StringUtils.isNotEmpty(nameSpace) && StringUtils.isNotEmpty(key)) {
            remove(nameSpace + "_" + key);
        }
    }

    public void set(String nameSpace, String key, Object value) {
        if (StringUtils.isNotEmpty(nameSpace) && StringUtils.isNotEmpty(key) && value != null) {
            set(nameSpace + "_" + key, value);
        }
    }

    public void set(String nameSpace, String key, int expried, Object value) {
        if (StringUtils.isNotEmpty(nameSpace) && StringUtils.isNotEmpty(key) && value != null) {
            set(nameSpace + "_" + key, expried, value);
        }
    }

    /**
     * 清空缓存
     */
    public void flushAll() throws Exception {
        Jedis jedis = getRedis();
        try {
            jedis.flushAll();
        } finally {
            jedis.close();
        }
    }

    /**
     * 测试缓存服务是否可连接
     */
    public boolean testConnect() {
        Jedis jedis = getRedis();
        try {
            jedis.isConnected();
            if ("PONG".equalsIgnoreCase(jedis.ping())) {
                return true;
            }
        } finally {
            jedis.close();
        }
        return false;
    }

    /**
     * 序列化
     */
    public byte[] serialize(Object object) {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream baos = null;
        try {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(object);
            byte[] bytes = baos.toByteArray();
            return bytes;
        } catch (Exception e) {
            logger.error("Exception occur when cache serialize 失败", e);
        } finally {
            if (oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                }
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }

    /**
     * 反序列化
     */
    public Object unserialize(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try {
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            return ois.readObject();
        } catch (Exception e) {
            logger.error("Exception occur when cache unserialize 失败", e);
        } finally {
            if (ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                }
            }
            if (bais != null) {
                try {
                    bais.close();
                } catch (IOException e) {
                }
            }
        }
        return null;
    }
}
