package com.ssyf.plugs.cache;

import cn.hutool.core.util.StrUtil;
import com.ssyf.plugs.cache.cache.AbstractCache;
import com.ssyf.plugs.cache.cache.EhcacheCache;
import com.ssyf.plugs.cache.cache.SecondLevelCache;
import com.ssyf.plugs.cache.cache.RedisCache;
import com.ssyf.plugs.cache.helper.CacheHelper;
import com.ssyf.plugs.cache.properties.CacheProperties;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 多级缓存管理器
 * @author huwei
 * @date 2022/11/28 20:55
 */
public class AdaptCacheManager implements CacheManager {

    private EhCacheCacheManager ehCacheCacheManager;

    private RedisTemplate<String, Object> redisTemplate;

    private CacheProperties cacheProperties;

    private Map<String , AbstractCache> cacheStore = new ConcurrentHashMap<>();

    private Set<String> cacheNames = new HashSet<>();

    private CacheCreator cacheCreator;

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

    private void init(){
        this.cacheNames.addAll(this.cacheProperties.getCacheNames());
        this.cacheNames.addAll(this.cacheProperties.getEhcacheCacheNames());

        if(this.redisTemplate != null && this.ehCacheCacheManager != null && this.cacheProperties.isSecondLevel()){
            //二级缓存方式
            this.cacheCreator = new SecondLevelCacheCreator(this.cacheProperties ,this.redisTemplate ,this.ehCacheCacheManager);
        }else if(this.redisTemplate != null){
            //redis缓存方式
            this.cacheCreator = new RedisCacheCreator(this.cacheProperties ,this.redisTemplate ,null);
        }else{
            //本地缓存
            this.cacheCreator = new EhcacheCacheCreator(this.cacheProperties ,null ,this.ehCacheCacheManager);
        }
    }

    @Override
    public Cache getCache(String name) {
        Cache cache = this.cacheStore.get(name);
        if(cache != null){
            return cache;
        }
        if(!this.cacheProperties.isDynamic() && !this.cacheNames.contains(name)){
            return null;
        }
        AbstractCache cacheCache = this.cacheCreator.create(name);
        this.cacheStore.put(name, cacheCache);
        this.cacheNames.add(name);
        return cacheCache;
    }

    @Override
    public Collection<String> getCacheNames() {
        return this.cacheNames;
    }

    /**
     * 清除本地缓存
     * @param name
     * @param key
     * @param uniqueKey
     */
    public void clearLocal(String name, Object key, String uniqueKey) {
        if(this.ehCacheCacheManager != null){
            Cache cache = CacheHelper.getOrCreateCache(name ,this.ehCacheCacheManager);
            cache.evict(key);
        }
        Cache cache = this.cacheStore.get(name);
        if(cache == null) {
            return ;
        }
        AbstractCache cacheCache = (AbstractCache) cache;
        //判断是否是自己发送的消息 如果是自己发送的就不需要清楚缓存了
        if (StrUtil.isBlank(uniqueKey) && cacheCache.getUniqueKey().equals(uniqueKey)) {
            return;
        }
        cacheCache.clearLocal(key);
    }

    /**
     * 缓存创建类
     * @author huwei
     * @date 2023/9/21 15:46
     */
    abstract class CacheCreator{
        protected CacheProperties cacheProperties;
        protected RedisTemplate<String, Object> redisTemplate;
        protected EhCacheCacheManager ehCacheCacheManager;
        CacheCreator(CacheProperties cacheProperties ,RedisTemplate<String, Object> redisTemplate ,EhCacheCacheManager ehCacheCacheManager){
            this.cacheProperties = cacheProperties;
            this.ehCacheCacheManager = ehCacheCacheManager;
            this.redisTemplate = redisTemplate;
        }

        /**
         * 创建缓存对象
         * @param name
         * @return
         */
        abstract AbstractCache create(String name);
    }

    /**
     * Ehcache缓存创建类
     * @author huwei
     * @date 2023/9/21 15:45
     */
    class EhcacheCacheCreator extends CacheCreator{
        EhcacheCacheCreator(CacheProperties cacheProperties, RedisTemplate<String, Object> redisTemplate, EhCacheCacheManager ehCacheCacheManager) {
            super(cacheProperties, redisTemplate, ehCacheCacheManager);
        }
        @Override
        public AbstractCache create(String name) {
            return new EhcacheCache(name ,this.cacheProperties ,this.ehCacheCacheManager);
        }
    }

    /**
     * redis缓存创建类
     * @author huwei
     * @date 2023/9/21 15:44
     */
    class RedisCacheCreator extends CacheCreator {
        RedisCacheCreator(CacheProperties cacheProperties, RedisTemplate<String, Object> redisTemplate, EhCacheCacheManager ehCacheCacheManager) {
            super(cacheProperties, redisTemplate, ehCacheCacheManager);
        }
        @Override
        AbstractCache create(String name) {
            return new RedisCache(name ,this.cacheProperties ,this.redisTemplate);
        }
    }

    /**
     * 二级缓存创建类
     * @author huwei
     * @date 2023/9/21 15:44
     */
    class SecondLevelCacheCreator extends CacheCreator {
        SecondLevelCacheCreator(CacheProperties cacheProperties, RedisTemplate<String, Object> redisTemplate, EhCacheCacheManager ehCacheCacheManager) {
            super(cacheProperties, redisTemplate, ehCacheCacheManager);
        }
        @Override
        AbstractCache create(String name) {
            return new SecondLevelCache(name ,this.redisTemplate ,this.ehCacheCacheManager ,this.cacheProperties);
        }
    }
}
