package edu.whut.smilepicturebackend.manager.cache;

import cn.hutool.json.JSONUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Service
@RequiredArgsConstructor
public class MyCacheManager {

    /**
     * 本地缓存
     */
    private final Cache<String, String> localCache = Caffeine.newBuilder()
            .initialCapacity(1024)
            .maximumSize(10_000L)  // 最大 10000 条
            .expireAfterWrite(Duration.ofMinutes(5))  // 缓存 5 分钟后移除
            .build();

    /**
     * 分布式缓存
     */
    private final StringRedisTemplate stringRedisTemplate;

    public <T> T getFromCacheOrDatabase(
            String cacheKey,
            Class<T> clazz,
            Supplier<T> dbSupplier,
            int redisExpireSeconds) {

        // 查询本地缓存
        String cachedValue = localCache.getIfPresent(cacheKey);
        if (cachedValue != null) {
            return JSONUtil.toBean(cachedValue, clazz);
        }

        // 查询 Redis 缓存
        ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
        cachedValue = opsForValue.get(cacheKey);
        if (cachedValue != null) {
            localCache.put(cacheKey, cachedValue);
            return JSONUtil.toBean(cachedValue, clazz);
        }

        // 执行数据库查询
        T dbValue = dbSupplier.get();

        // 更新 Redis 缓存
        cachedValue = JSONUtil.toJsonStr(dbValue);
        opsForValue.set(cacheKey, cachedValue, redisExpireSeconds, TimeUnit.SECONDS);
        // 写入本地缓存
        localCache.put(cacheKey, cachedValue);
        return dbValue;
    }
}
