package com.ssyf.plugs.cache.cache;

import cn.hutool.core.util.ObjectUtil;
import com.ssyf.plugs.cache.CacheMessage;
import com.ssyf.plugs.cache.helper.CacheHelper;
import com.ssyf.plugs.cache.properties.CacheProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.data.redis.core.RedisTemplate;

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

/**
 * 缓存器
 * @author huwei
 * @date 2022/11/29 12:42
 */
@Slf4j
public class SecondLevelCache extends AbstractCache {

    private RedisTemplate<String, Object> redisTemplate;

    private EhCacheCacheManager ehCacheCacheManager;

    public SecondLevelCache(String name, RedisTemplate<String, Object> redisTemplate , EhCacheCacheManager ehCacheCacheManager , CacheProperties cacheProperties) {
        super(name,cacheProperties);
        this.redisTemplate = redisTemplate;
        this.ehCacheCacheManager = ehCacheCacheManager;
    }

    /**
     * 执行底层查询操作
     * @param key
     * @return
     */
    @Override
    protected Object lookup(Object key) {
        //先取一级缓存
        Cache cache = CacheHelper.getOrCreateCache(this.getName() ,this.ehCacheCacheManager);
        Object value = cache.get(key);
        if(ObjectUtil.isNotEmpty(value)){
            log.debug("从ehcache中获取数据：{}" ,value);
            return CacheHelper.parseValue(value);
        }

        //在取二级缓存
        String redisKey = redisKey(key);
        value = this.redisTemplate.opsForValue().get(redisKey);
        if(ObjectUtil.isNotEmpty(value)) {
            log.debug("从redis中获取数据：{}",value);
            //本地缓存
            CacheHelper.getOrCreateCache(this.getName() ,this.ehCacheCacheManager).put(key,value);
        }
        return CacheHelper.parseValue(value);
    }

    @Override
    public Object getNativeCache() {
        return this;
    }

    @Override
    public void put(Object key, Object value) {
        if (!super.isAllowNullValues() && ObjectUtil.isEmpty(value)) {
            this.evict(key);
            return;
        }

        //一级缓存
        Cache cache = CacheHelper.getOrCreateCache(this.getName() ,this.ehCacheCacheManager);
        cache.put(key ,CacheHelper.wrapValue(value));

        //二级缓存
        long expire =  getExpire(this.getName() ,key);
        String redisKey = redisKey(key);
        if(expire > 0) {
            this.redisTemplate.opsForValue().set(redisKey, CacheHelper.wrapValue(value), expire, TimeUnit.MILLISECONDS);
        }else {
            this.redisTemplate.opsForValue().set(redisKey, CacheHelper.wrapValue(value));
        }
        //消息广播
        push(new CacheMessage(this.getName() ,key ,this.getUniqueKey()));
    }

    @Override
    public void evict(Object key) {
        //删除redis中的缓存
        this.redisTemplate.delete(redisKey(key));
        push(new CacheMessage(this.getName() ,key ,this.getUniqueKey()));
        //删除一级缓存
        Cache cache = CacheHelper.getOrCreateCache(this.getName() ,this.ehCacheCacheManager);
        cache.evict(key);
    }

    @Override
    public void clear() {
        Set<String> scan = this.redisTemplate.keys(this.getName().concat(":*"));
        this.redisTemplate.delete(scan);

        //消息通知
        push(new CacheMessage(this.getName(),null, this.getUniqueKey()));

        //删除一级缓存
        Cache cache = CacheHelper.getOrCreateCache(this.getName() ,this.ehCacheCacheManager);
        cache.clear();
    }

    /**
     * 清除多级缓存值
     * @param key
     */
    @Override
    public void clearLocal(Object key) {
        //删除一级缓存
        Cache cache = CacheHelper.getOrCreateCache(this.getName() ,this.ehCacheCacheManager);
        if(key == null){
            cache.clear();
        }else{
            cache.evict(key);
        }
    }


    /**
     * 通知其他缓存删除一级缓存
     * @param message
     */
    private void push(CacheMessage message) {
        this.redisTemplate.convertAndSend(this.cacheProperties.getTopic(), message);
    }

    private String redisKey(Object key){
        return this.getName() + ":" + key.toString();
    }

}
