package com.games.gateway.utils;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author mzc
 */
@Service
public class PathWhiteCache implements InitializingBean {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisKeyUtils redisKeyUtils;

    private LoadingCache<String, List<String>> pathWhiteLocalCache;

    public String getRedisKey() {
        String redisKey = redisKeyUtils.pathWhiteKey();
        return redisKey;
    }

    /**
     * 检测path是否是白名单
     *
     * @param path
     * @return
     */
    public Boolean exists(String path) {
        String key = getRedisKey();
        List<String> pathWhiteList = pathWhiteLocalCache.get(key);
        return pathWhiteList.contains(path);
    }

    /**
     * 缓存
     *
     * @param pathList
     */
    public void cache(List<String> pathList) {
        String key = getRedisKey();
        //先添加到redis
        for (String path : pathList) {
            stringRedisTemplate.opsForSet().add(key, path);
        }
        //再添加本地缓存
        List<String> pathWhiteList = getPathWhiteList(key);
        pathWhiteLocalCache.put(key, pathWhiteList);

    }

    /**
     * 删除缓存
     *
     * @param path
     */
    public void invalidate(String path) {
        String key = redisKeyUtils.pathWhiteKey();
        //删除redis member
        stringRedisTemplate.opsForSet().remove(path);

        //再删除本地缓存
        List<String> pathWhiteList = getPathWhiteList(key);
        pathWhiteLocalCache.put(key, pathWhiteList);
    }

    /**
     * 获取白名单列表
     *
     * @param key
     * @return
     */
    public List<String> getPathWhiteList(String key) {
        Set<String> members = stringRedisTemplate.opsForSet().members(key);
        if (CollectionUtils.isEmpty(members)) {
            return Lists.newArrayList();
        } else {
            List<String> pathWhiteList = members.stream().collect(Collectors.toList());
            return pathWhiteList;
        }
    }

    /**
     * 初始化 JVM Cache
     */
    @Override
    public void afterPropertiesSet() {
        pathWhiteLocalCache = Caffeine.newBuilder()
                .expireAfterWrite(1, TimeUnit.HOURS)
                .maximumSize(100)
                .build(key -> {
                    if (!stringRedisTemplate.hasKey(key)) {
                        return Lists.newArrayList();
                    }
                    return getPathWhiteList(key);
                });
    }
}
