package cc.smtweb.framework.core.cache;

import cc.smtweb.framework.core.cache.redis.RedisBroadcastEvent;
import cc.smtweb.framework.core.db.cache.EntityCache;
import cc.smtweb.framework.core.db.cache.ModelTableCache;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 内存缓存管理器，管理lazy加载的缓存，长时间不使用会失效
 */
@Slf4j
public class CacheManager {
    //所有缓存对象
    private final Map<String, AbstractCache> cacheMap = new HashMap<>();
    private final Map<Class, AbstractCache> cacheMapCls = new HashMap<>();
    //记录顺序用
    private List<AbstractCache> listCache = new ArrayList<>();
    //缓存清理线程池
    private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

    public AbstractCache getCache(String ident) {
        final AbstractCache cache = cacheMap.get(ident.toUpperCase());
        if (cache != null && cache.isNotInited()) {
            cache.init();
        }
        return cache;
    }

    public <T extends AbstractCache> T getCache(Class<T> clazz) {
        final T cache = (T) cacheMapCls.get(clazz);
        if (cache != null && cache.isNotInited()) {
            cache.init();
        }
        return cache;
    }

    public static CacheManager getIntance() {
        return SpringUtil.getBean(CacheManager.class);
    }

    // 初始化cache
    public boolean install(AbstractCache cache) {
        cache.install(executorService);
        if (cacheMap.putIfAbsent(cache.getIdent(), cache) == null) {
            cacheMapCls.put(cache.getClass(), cache);
            listCache.add(cache);
            return true;
        }

        return false;
    }

    /**
     * 启动时的初始化及预加载
     * 1、按依赖关系排序
     * 2、预加载（lazy模式不从库加载）
     */
    public void init() {
        listCache.sort((o1, o2) -> {
            //o1依赖o2
            if (isContains(o1.getDepends(), o2.getIdent())) return 1;
            //o2依赖o1
            if (isContains(o2.getDepends(), o1.getIdent())) return -1;

            return 0;//getPluginIndex(o1) - getPluginIndex(o2);
        });
        for (AbstractCache cache : listCache) {
            if (cache.isNotInited()) {
                cache.init();
            }
        }
        //按表加载并初始化
        for (ModelTable table : ModelTableCache.getInstance().getAll()) {
            if (table.isNeedCache() && !cacheMap.containsKey(table.getName())) {
                EntityCache cache = new EntityCache(table.getName());
                cache.install(executorService);
                cacheMapCls.put(cache.getClass(), cache);
                cacheMap.put(table.getName(), cache);
            }
        }
    }

    public void refresh() {
        listCache.sort((o1, o2) -> {
            //o1依赖o2
            if (isContains(o1.getDepends(), o2.getIdent())) return 1;
            //o2依赖o1
            if (isContains(o2.getDepends(), o1.getIdent())) return -1;

            return 0;//getPluginIndex(o1) - getPluginIndex(o2);
        });
        for (AbstractCache cache : listCache) {
            cache.init();
        }
    }

    private boolean isContains(String[] src, String dest) {
        if (src == null || src.length == 0) return false;
        for (String s : src) {
            if (s.trim().equals(dest)) return true;
        }
        return false;
    }

    @EventListener
    public void onRedisBroadcastEvent(RedisBroadcastEvent event) {
        AbstractCache cache = getCache(event.getIdent());
        if (cache == null) {
            log.info("接收到不存在的缓存更新！（" + event.toString() + "）");
            return;
        }
        cache.syncCache(event);
    }
}
