package ink.wgink.redis.cache.manager.app;

import ink.wgink.interfaces.manager.IAppTokenService;
import ink.wgink.pojo.app.AppToken;
import ink.wgink.pojo.app.AppTokenUser;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName: RedisAppTokenManager
 * @Description: redis app token 管理器
 * @Author: wanggeng
 * @Date: 2021/11/29 4:25 下午
 * @Version: 1.0
 */
@Primary
@Service
public class RedisAppTokenService implements IAppTokenService {

    private static final Logger LOG = LoggerFactory.getLogger(RedisAppTokenService.class);
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public AppToken getToken(String token) {
        String tokenKey = TOKEN_HASH_KEY + token;
        AppToken appToken = (AppToken) redisTemplate.opsForValue().get(tokenKey);
        if (appToken != null) {
            appToken.setLastTime(System.currentTimeMillis());
            redisTemplate.opsForValue().set(tokenKey, appToken, 10, TimeUnit.MINUTES);
        }
        return appToken;
    }

    @Override
    public void addToken(String token, AppToken.AppTokenTypeEnum appTokenTypeEnum, AppTokenUser appTokenUser) {
        AppToken appToken = new AppToken();
        appToken.setToken(token);
        appToken.setAppTokenTypeEnum(appTokenTypeEnum);
        appToken.setLastTime(System.currentTimeMillis());
        appToken.setAppTokenUser(appTokenUser);
        appToken.setUserId(appTokenUser.getId());

        Set<String> keys = redisTemplate.keys(TOKEN_HASH_KEY + "*");
        List<AppToken> existAppTokens = redisTemplate.opsForValue().multiGet(keys);
        for (AppToken existAppToken : existAppTokens) {
            if (StringUtils.equals(appToken.getAppTokenUser().getId(), existAppToken.getUserId())) {
                redisTemplate.delete(TOKEN_HASH_KEY + existAppToken.getToken());
                break;
            }
        }
        redisTemplate.opsForValue().set(TOKEN_HASH_KEY + token, appToken, 10, TimeUnit.MINUTES);
    }

    @Override
    public List<AppTokenUser> listCurrentUsers() {
        List<AppTokenUser> users = new ArrayList<>();
        Set<String> keys = redisTemplate.keys(TOKEN_HASH_KEY + "*");
        List<AppToken> existAppTokens = redisTemplate.opsForValue().multiGet(keys);
        for (AppToken existAppToken : existAppTokens) {
            users.add(existAppToken.getAppTokenUser());
        }
        return users;
    }

    @Override
    public void clearTimeoutToken() {
        long currentTime = System.currentTimeMillis();
        Set<String> clearTokenKeys = new HashSet<>(16);
        Set<String> keys = redisTemplate.keys(TOKEN_HASH_KEY + "*");
        List<AppToken> existAppTokens = redisTemplate.opsForValue().multiGet(keys);
        for (AppToken existAppToken : existAppTokens) {
            if (currentTime - existAppToken.getLastTime() > 600000L) {
                clearTokenKeys.add(TOKEN_HASH_KEY + existAppToken.getToken());
            }
        }
        redisTemplate.delete(clearTokenKeys);
        LOG.trace(">>>>>> count of timeout token: {}", clearTokenKeys.size());
    }
}
