package com.aps.common.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 轻量级全局缓存工具类（基于ConcurrentHashMap）
 * 支持：过期时间、自动清理过期缓存、线程安全、批量删除
 */
public class GlobalCacheUtil {
    // 核心缓存容器（ConcurrentHashMap保证线程安全）
    private static final Map<String, CacheEntry> CACHE_MAP = new ConcurrentHashMap<>();
    // 定时清理过期缓存的线程池（单线程即可）
    private static final ScheduledExecutorService CLEAN_EXECUTOR = Executors.newSingleThreadScheduledExecutor(r -> {
        Thread t = new Thread(r, "cache-clean-thread");
        t.setDaemon(true); // 守护线程，不阻塞程序退出
        return t;
    });

    // 缓存条目：封装值 + 过期时间
    private static class CacheEntry {
        Object value;       // 缓存值
        long expireTime;    // 过期时间戳（毫秒）：0表示永不过期

        public CacheEntry(Object value, long expireTime) {
            this.value = value;
            this.expireTime = expireTime;
        }
    }

    // 静态初始化：启动定时清理任务（每5分钟清理一次过期缓存）
    static {
        CLEAN_EXECUTOR.scheduleAtFixedRate(
                () -> CACHE_MAP.entrySet().removeIf(entry -> {
                    long expireTime = entry.getValue().expireTime;
                    return expireTime != 0 && System.currentTimeMillis() > expireTime;
                }),
                5, 5, TimeUnit.MINUTES
        );
    }

    // ======================== 核心方法 ========================
    /**
     * 存入缓存（永不过期）
     * @param key   缓存键
     * @param value 缓存值
     */
    public static void put(String key, Object value) {
        put(key, value, 0, TimeUnit.MILLISECONDS);
    }

    /**
     * 存入缓存（指定过期时间）
     * @param key      缓存键
     * @param value    缓存值
     * @param timeout  过期时长
     * @param timeUnit 时间单位
     */
    public static void put(String key, Object value, long timeout, TimeUnit timeUnit) {
        if (key == null || value == null) {
            return;
        }
        long expireTime = timeout <= 0 ? 0 : System.currentTimeMillis() + timeUnit.toMillis(timeout);
        CACHE_MAP.put(key, new CacheEntry(value, expireTime));
    }

    /**
     * 获取缓存值（自动过滤过期值）
     * @param key 缓存键
     * @param <T> 泛型，避免强制类型转换
     * @return 缓存值（过期/不存在返回null）
     */
    @SuppressWarnings("unchecked")
    public static <T> T get(String key) {
        CacheEntry entry = CACHE_MAP.get(key);
        if (entry == null) {
            return null;
        }
        // 检查是否过期
        if (entry.expireTime != 0 && System.currentTimeMillis() > entry.expireTime) {
            CACHE_MAP.remove(key); // 主动移除过期缓存
            return null;
        }
        return (T) entry.value;
    }

    /**
     * 删除指定缓存
     * @param key 缓存键
     */
    public static void remove(String key) {
        CACHE_MAP.remove(key);
    }

    /**
     * 清空所有缓存
     */
    public static void clear() {
        CACHE_MAP.clear();
    }

    /**
     * 获取缓存大小
     */
    public static int size() {
        return CACHE_MAP.size();
    }

    // 关闭定时任务（程序退出时调用）
    public static void shutdown() {
        CLEAN_EXECUTOR.shutdown();
    }

    // ======================== 测试示例 ========================
    public  void test() throws InterruptedException {
        // 1. 存入永不过期缓存
        GlobalCacheUtil.put("user:1", "张三");
        System.out.println("获取user:1：" + GlobalCacheUtil.get("user:1")); // 输出：张三

        // 2. 存入1秒后过期的缓存
        GlobalCacheUtil.put("code:123", "666666", 1, TimeUnit.SECONDS);
        System.out.println("立即获取code:123：" + GlobalCacheUtil.get("code:123")); // 输出：666666

        // 3. 等待2秒后获取（已过期）
        Thread.sleep(2000);
        System.out.println("2秒后获取code:123：" + GlobalCacheUtil.get("code:123")); // 输出：null

        // 4. 清空缓存
        GlobalCacheUtil.clear();
        System.out.println("清空后缓存大小：" + GlobalCacheUtil.size()); // 输出：0
    }
}
