package com.brilliance.mda.support.cache.impl;

import com.brilliance.mda.runtime.mda.RuleExecuteException;
import com.brilliance.mda.support.cache.ICache;
import com.brilliance.mda.support.cache.serializer.ICacheSerializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

public class RedisCache<V> implements ICache<String, V> {

    private final Logger logger = LoggerFactory.getLogger(RedisCache.class);

    private String cacheName;

    private RedisTemplate<String, Object> redisTemplate;

    private ICacheSerializer serializer;

    private long expireTime;

    public RedisCache(String cacheName, RedisTemplate<String, Object> redisTemplate, ICacheSerializer serializer, long expireTime) {
        this.cacheName = cacheName;
        this.redisTemplate = redisTemplate;
        this.serializer = serializer;
        this.expireTime = expireTime;
    }

    @Override
    public String store(V v) {
        String key = generateKey();
        this.store(key, v);
        return key;
    }

    @Override
    public void store(String key, V v) {
        try {
            long time1 = System.currentTimeMillis();
            byte[] bytes = serializer.writeToByteArray(v);
            if(bytes == null){
                logger.debug("{}使用{}序列化 Key:{},Length:{},Timing:{}ms",cacheName,serializer.getName(),key,0,System.currentTimeMillis() - time1);
                return;
            }
            logger.debug("{}使用{}序列化 Key:{},Length:{},Timing:{}ms",cacheName,serializer.getName(),key,bytes.length,System.currentTimeMillis() - time1);

            time1 = System.currentTimeMillis();
            redisTemplate.opsForValue().set(key, bytes, expireTime, TimeUnit.SECONDS);
            logger.debug("{}写入redis Key:{},Length:{},Timing:{}ms",cacheName,key,bytes.length,System.currentTimeMillis() - time1);

        } catch (Exception e) {
            logger.error(cacheName+"使用"+serializer.getName() + "序列化保存缓存失败", e);
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public V get(String s) {
        try {
            if (null == s) {
                logger.error("RedisCache get with null key");
                return null;
            }
            long time1 = System.currentTimeMillis();
            byte[] bytes = (byte[]) redisTemplate.opsForValue().get(s);
            if (null == bytes){
                logger.debug("从redis读取Key:{},Length:{},Timing:{}ms",s,0,System.currentTimeMillis() - time1);
                return null;
            }
            long time2 = System.currentTimeMillis();
            logger.debug("从redis读取Key:{},Length:{},Timing:{}ms",s,bytes.length,System.currentTimeMillis() - time1 );
            V v = serializer.readFromByteArray(bytes);

            logger.debug("{}使用{}反序列化Key:{},Length:{},Timing:{} ms", cacheName,serializer.getName(),s,bytes.length, System.currentTimeMillis() - time2);

            return v;
        } catch (Exception e) {
            logger.error(serializer.getName() + "反序列化失败", e);
            if(e instanceof RuleExecuteException){
                throw e;
            }else{
                throw new RuleExecuteException(serializer.getName() + "反序列化失败",e);
            }
        }
    }

    @Override
    public void remove(String s) {
        redisTemplate.delete(s);
    }

    @Override
    public String generateKey() {
        return cacheName + "-" + UUID.randomUUID();
    }

    @Override
    public void keeplive(String key) {
        if(key == null){
            return;
        }
        redisTemplate.expire(key,expireTime,TimeUnit.SECONDS);
    }

    @Override
    public void cleanup() {
        logger.info("RedisCache not clean up .");
    }

    @Override
    public boolean contains(String key) {
        return redisTemplate.hasKey(key);
    }
}
