package com.ai.da.common.utils;

import com.ai.da.model.vo.SysFileVO;
import com.google.common.cache.*;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @author: yanglei
 * @description: 本地缓存工具
 * @create: 2022-08-11 9:23
 **/
@Slf4j
public final class LocalCacheUtils {
    /**
     * token
     */
    private static LoadingCache<String, String> tokenCache = loadTokenCache();

    /**
     * 缓存接口这里是LoadingCache，LoadingCache在缓存项不存在时可以自动加载缓存
     */
    private static LoadingCache<String, String> loadTokenCache() {
        LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder()
                .concurrencyLevel(10)
                .expireAfterWrite(24 * 7 - 1, TimeUnit.HOURS)
                .initialCapacity(100)
                .maximumSize(10000)
                .recordStats()
                .build(new CacheLoader<String, String>() {
                    @Override
                    public String load(String key) throws Exception {
                        return "null";
                    }
                });
        return tokenCache;
    }

    /**
     * 邮箱,短信验证码
     */
    private static LoadingCache<String, String> emailCache = CacheBuilder.newBuilder()
            //设置并发级别为5，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            //设置写缓存后10分钟过期,防止跨洲发送慢失效问题
            .expireAfterWrite(60 * 30, TimeUnit.SECONDS)
            //刷新机制 每隔一定时间刷新缓存loader 只有调用get具体的操作才生效(懒加载) 不设置则不刷新
//            .refreshAfterWrite(60, TimeUnit.SECONDS)
            //设置缓存容器的初始容量为100
            .initialCapacity(100)
            //设置缓存最大容量10000，超过100之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(10000)
            //设置要统计缓存的命中率
            .recordStats()
            //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) throws Exception {
                    return "null";
                }
            });

    /**
     * 系统文件 最大最小值
     */
    private static LoadingCache<String, Long> sysFileMaxAndMinCache = CacheBuilder.newBuilder()
            //设置并发级别为5，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            //设置写缓存后一天过期
            .expireAfterWrite(60 * 60 * 24, TimeUnit.SECONDS)
            //设置缓存容器的初始容量为100
            .initialCapacity(100)
            //设置缓存最大容量50000，超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(500)
            //设置要统计缓存的命中率
            .recordStats()
            //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
            .build(new CacheLoader<String, Long>() {
                @Override
                public Long load(String key) throws Exception {
                    return 0L;
                }
            });
    /**
     * 系统文件本地缓存 id -> path
     */
    private static LoadingCache<Long, SysFileVO> sysFileCache = CacheBuilder.newBuilder()
            //设置并发级别为5，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            //设置写缓存后一天过期
            .expireAfterWrite(60 * 60 * 24, TimeUnit.SECONDS)
            //设置缓存容器的初始容量为100
            .initialCapacity(100)
            //设置缓存最大容量50000，超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(50000)
            //设置要统计缓存的命中率
            .recordStats()
            //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
            .build(new CacheLoader<Long, SysFileVO>() {
                @Override
                public SysFileVO load(Long key) throws Exception {
                    return new SysFileVO();
                }
            });

    /**
     * 系统文件本地缓存 level1-> sysFile 数组
     */
    private static LoadingCache<String, List<SysFileVO>> sysFileLevelType1Cache = CacheBuilder.newBuilder()
            //设置并发级别为5，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            //设置写缓存后一天过期
            .expireAfterWrite(60 * 60 * 24, TimeUnit.SECONDS)
            //设置缓存容器的初始容量为15000
            .initialCapacity(15000)
            //设置缓存最大容量50000，超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(50000)
            //设置要统计缓存的命中率
            .recordStats()
            //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
            .build(new CacheLoader<String, List<SysFileVO>>() {
                @Override
                public List<SysFileVO> load(String key) throws Exception {
                    return new ArrayList();
                }
            });

    /**
     * design文件进度统计
     */
    private static LoadingCache<Long, List<String>> designProcessCache = CacheBuilder.newBuilder()
            //设置并发级别为10，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(10)
            //设置写缓存后5分钟过期
            .expireAfterWrite(60 * 5, TimeUnit.SECONDS)
            //设置缓存容器的初始容量为100
            .initialCapacity(5)
            //设置缓存最大容量50000，超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(100)
            //设置要统计缓存的命中率
            .recordStats()
            //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
            .build(new CacheLoader<Long, List<String>>() {
                @Override
                public List<String> load(Long key) throws Exception {
                    return Collections.EMPTY_LIST;
                }
            });

    /**
     * aida 接口限流(先粗暴做)
     */
    private static LoadingCache<String, Integer> aidaInterfaceCurrentLimiting = CacheBuilder.newBuilder()
            //设置并发级别为5，并发级别是指可以同时写缓存的线程数
            .concurrencyLevel(20)
            //设置写缓存后30天过期
            .expireAfterWrite(60 * 60 * 24 * 30, TimeUnit.SECONDS)
            //设置缓存容器的初始容量为100
            .initialCapacity(5)
            //设置缓存最大容量50000，超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
            .maximumSize(20)
            //设置要统计缓存的命中率
            .recordStats()
            //build方法中可以指定CacheLoader，在缓存不存在时通过CacheLoader的实现自动加载缓存
            .build(new CacheLoader<String, Integer>() {
                @Override
                public Integer load(String key) throws Exception {
                    return 0;
                }
            });

    /**
     * 添加token本地缓存
     *
     * @param key
     * @param value
     */
    public static void setTokenCache(String key, String value) {
        tokenCache.put(key, value);
    }

    /**
     * 获取token本地缓存
     *
     * @param key
     * @return
     */
    public static String getTokenCache(String key) {
        try {
            String value = tokenCache.get(key);
            if ("null".equals(value)) {
                return null;
            }
            return value;
        } catch (ExecutionException e) {
            log.error("getTokenCache方法错误", e);
        }
        return null;
    }

    /**
     * 删除token本地缓存(登出)
     *
     * @param key
     * @return
     */
    public static void delTokenCache(String key) {
        try {
            tokenCache.invalidate(key);
        } catch (Exception e) {
            log.error("delTokenCache方法错误", e);
        }
    }

    /**
     * 添加验证码本地缓存
     *
     * @param key
     * @param value
     */
    public static void setVerifyCodeCache(String key, String value) {
        emailCache.put(key, value);
    }

    /**
     * 获取验证码本地缓存
     *
     * @param key
     * @return
     */
    public static String getVerifyCodeCache(String key) {
        try {
            String value = emailCache.get(key);
            if ("null".equals(value)) {
                return null;
            }
            return value;
        } catch (ExecutionException e) {
            log.error("getVerifyCodeCache方法错误", e);
        }
        return null;
    }

    /**
     * 添加系统文本地缓存
     *
     * @param key
     * @param sysFile
     */
    public static void setSysFileCache(Long key, SysFileVO sysFile) {
        sysFileCache.put(key, sysFile);
    }

    /**
     * 获取系统文件本地缓存
     *
     * @param key
     * @return
     */
    public static SysFileVO getSysFileCache(Long key) {
        try {
            SysFileVO value = sysFileCache.get(key);
            return value;
        } catch (ExecutionException e) {
            log.error("getSysFileCache方法错误", e);
        }
        return null;
    }

    /**
     * 清除所有系统文件本地缓存
     *
     * @return
     */
    public static void clearAllSysFileCache() {
        try {
            sysFileCache.invalidateAll();
        } catch (Exception e) {
            log.error("clearAllSysFileCache方法错误", e);
        }
    }

    /**
     * 添加系统文本地缓存,通过类型
     *
     * @param level1Type
     * @param sysFileList
     */
    public static void setSysFileCacheByLevel2Type(String level1Type, List<SysFileVO> sysFileList) {
        sysFileLevelType1Cache.put(level1Type, sysFileList);
    }

    /**
     * 获取系统文件本地缓存
     *
     * @param level2Type
     * @return
     */
    public static List<SysFileVO> getSysFileCacheByLevel2Type(String level2Type) {
        try {
            return sysFileLevelType1Cache.get(level2Type);
        } catch (ExecutionException e) {
            log.error("getSysFileCacheByLevel1Type方法错误", e);
        }
        return null;
    }

    /**
     * 清除所有系统文件本地缓存
     *
     * @return
     */
    public static void clearAllSysFileCacheByLevel2Type() {
        try {
            sysFileLevelType1Cache.invalidateAll();
        } catch (Exception e) {
            log.error("clearAllSysFileCacheByLevel2Type方法错误", e);
        }
    }

    /**
     * 添加系统文件范围最大最小值本地缓存
     *
     * @param key
     * @param value
     */
    public static void setFileMaxMinValueCache(String key, Long value) {
        sysFileMaxAndMinCache.put(key, value);
    }

    /**
     * 获取系统文件范围最大最小值本地缓存
     *
     * @param key
     * @return
     */
    public static Long getFileMaxMinValueCache(String key) {
        try {
            Long value = sysFileMaxAndMinCache.get(key);
            if (0L == value) {
                return null;
            }
            return value;
        } catch (ExecutionException e) {
            log.error("getFileMaxMinValueCache方法错误", e);
        }
        return null;
    }

    /**
     * 清除所有系统文件范围最大最小值本地缓存
     *
     * @return
     */
    public static void clearAllMaxMinValueCache() {
        try {
            sysFileMaxAndMinCache.invalidateAll();
        } catch (Exception e) {
            log.error("clearAllMaxMinValueCache方法错误", e);
        }
    }

    /**
     * 添加系design文件进度统计
     *
     * @param key
     * @param value
     */
    public static void setDesignProcessCache(Long key, List<String> value) {
        designProcessCache.put(key, value);
    }

    /**
     * 获取design文件进度统计
     *
     * @param key
     * @return
     */
    public static List<String> getDesignProcessCache(Long key) {
        try {
            List<String> value = designProcessCache.get(key);
            return value;
        } catch (ExecutionException e) {
            log.error("getDesignProcessCache方法错误", e);
        }
        return null;
    }

    /**
     * 进度统计完后 删除进度
     *
     * @param key
     * @return
     */
    public static void delDesignProcessCache(Long key) {
        try {
            designProcessCache.invalidate(key);
        } catch (Exception e) {
            log.error("delDesignProcessCache方法错误", e);
        }
    }

    /**
     * 设置本次接口流量数
     *
     * @param key
     * @param value
     */
    public static void setAidaInterfaceCurrentLimitingCache(String key, Integer value) {
        aidaInterfaceCurrentLimiting.put(key, value);
    }

    /**
     * 获取本次接口流量数
     *
     * @param key
     * @return
     */
    public static Integer getAidaInterfaceCurrentLimitingCache(String key) {
        try {
            return aidaInterfaceCurrentLimiting.get(key);
        } catch (ExecutionException e) {
            log.error("getAidaInterfaceCurrentLimitingCache方法错误", e);
        }
        return null;
    }

    /**
     * 预签名URL缓存
     */
    private static LoadingCache<String, String> presignedUrlCache = CacheBuilder.newBuilder()
            .concurrencyLevel(10)
            .expireAfterWrite((24 * 60 - 1), TimeUnit.MINUTES)
            .initialCapacity(100)
            .maximumSize(10000)
            .recordStats()
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) throws Exception {
                    return "null";
                }
            });

    /**
     * 添加预签名URL到缓存
     *
     * @param key   URL的唯一标识
     * @param value 预签名URL
     */
    public static void setPresignedUrlCache(String key, String value) {
        presignedUrlCache.put(key, value);
    }

    /**
     * 获取预签名URL
     *
     * @param key URL的唯一标识
     * @return 预签名URL，如果不存在则返回null
     */
    public static String getPresignedUrlCache(String key) {
        try {
            String value = presignedUrlCache.get(key);
            if ("null".equals(value)) {
                return null;
            }
            return value;
        } catch (ExecutionException e) {
            log.error("getPresignedUrlCache方法错误", e);
        }
        return null;
    }

}
