package com.example.demo.service;

import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

/**
 * Redis Token 服务
 * 用于管理用户 JWT Token 的存储、验证和删除
 * 当 redis.enabled=false 时，所有方法将返回默认值，不访问 Redis
 */
@Service
public class RedisTokenService {

    private static final Logger logger = LoggerFactory.getLogger(RedisTokenService.class);

    /**
     * Token 存储的 key 前缀
     * 格式: token:{username}:{tokenId}
     */
    private static final String TOKEN_PREFIX = "token:";

    /**
     * 用户 Token 集合的 key 前缀
     * 格式: user_tokens:{username}
     * 存储该用户所有有效的 token
     */
    private static final String USER_TOKENS_PREFIX = "user_tokens:";

    @org.springframework.beans.factory.annotation.Autowired(required = false)
    private StringRedisTemplate redisTemplate;

    @Value("${redis.token.expire-seconds:86400}")
    private long tokenExpireSeconds;

    @Value("${redis.enabled:true}")
    private boolean redisEnabled;

    /**
     * 保存 Token 到 Redis（使用默认过期时间）
     * 
     * @param username 用户名
     * @param token    JWT Token
     */
    public void saveToken(String username, String token) {
        saveToken(username, token, tokenExpireSeconds);
    }

    /**
     * 保存 Token 到 Redis（使用指定过期时间）
     * 
     * @param username      用户名
     * @param token         JWT Token
     * @param expireSeconds 过期时间（秒）
     */
    public void saveToken(String username, String token, long expireSeconds) {
        if (!redisEnabled || redisTemplate == null) {
            logger.debug("Redis 已禁用，跳过 Token 保存: username={}", username);
            return;
        }
        try {
            String tokenKey = getTokenKey(username, token);
            String userTokensKey = getUserTokensKey(username);

            // 保存 token -> username 映射
            redisTemplate.opsForValue().set(tokenKey, username, expireSeconds, TimeUnit.SECONDS);

            // 将 token 添加到用户的 token 集合中
            redisTemplate.opsForSet().add(userTokensKey, token);
            redisTemplate.expire(userTokensKey, expireSeconds, TimeUnit.SECONDS);

            logger.info("Token 已保存到 Redis: username={}, expireSeconds={}", username, expireSeconds);
        } catch (Exception e) {
            logger.error("保存 Token 到 Redis 失败: username={}, error={}", username, e.getMessage());
            // 不抛出异常，允许在 Redis 不可用时降级运行
        }
    }

    /**
     * 验证 Token 是否有效（存在于 Redis 中）
     * 
     * @param username 用户名
     * @param token    JWT Token
     * @return true 如果 token 有效
     */
    public boolean isTokenValid(String username, String token) {
        if (!redisEnabled || redisTemplate == null) {
            // Redis 禁用时，直接返回 true，依赖 JWT 本身的验证
            return true;
        }
        try {
            String tokenKey = getTokenKey(username, token);
            Boolean exists = redisTemplate.hasKey(tokenKey);
            if (Boolean.TRUE.equals(exists)) {
                return true;
            }
            // Token 不在 Redis 中，可能是登录时未保存或 Redis 数据丢失
            // 降级为允许通过（依赖 JWT 本身的验证）
            logger.debug("Token 不在 Redis 中，降级为允许通过: username={}", username);
            return true;
        } catch (Exception e) {
            logger.warn("验证 Token 时 Redis 访问失败，降级为允许通过: username={}, error={}", username, e.getMessage());
            // Redis 不可用时降级为允许通过（依赖 JWT 本身的验证）
            return true;
        }
    }

    /**
     * 删除指定 Token（用户登出）
     * 
     * @param username 用户名
     * @param token    JWT Token
     */
    public void removeToken(String username, String token) {
        if (!redisEnabled || redisTemplate == null) {
            return;
        }
        try {
            String tokenKey = getTokenKey(username, token);
            String userTokensKey = getUserTokensKey(username);

            // 删除 token
            redisTemplate.delete(tokenKey);

            // 从用户 token 集合中移除
            redisTemplate.opsForSet().remove(userTokensKey, token);

            logger.info("Token 已从 Redis 删除: username={}", username);
        } catch (Exception e) {
            logger.error("从 Redis 删除 Token 失败: username={}, error={}", username, e.getMessage());
        }
    }

    /**
     * 删除用户的所有 Token（强制登出所有设备）
     * 
     * @param username 用户名
     */
    public void removeAllTokens(String username) {
        if (!redisEnabled || redisTemplate == null) {
            return;
        }
        try {
            String userTokensKey = getUserTokensKey(username);

            // 获取用户所有 token
            Set<String> tokens = redisTemplate.opsForSet().members(userTokensKey);

            if (tokens != null && !tokens.isEmpty()) {
                // 删除所有 token
                for (String token : tokens) {
                    String tokenKey = getTokenKey(username, token);
                    redisTemplate.delete(tokenKey);
                }
            }

            // 删除用户 token 集合
            redisTemplate.delete(userTokensKey);

            logger.info("用户所有 Token 已从 Redis 删除: username={}, count={}", 
                username, tokens != null ? tokens.size() : 0);
        } catch (Exception e) {
            logger.error("从 Redis 删除用户所有 Token 失败: username={}, error={}", username, e.getMessage());
        }
    }

    /**
     * 刷新 Token 过期时间
     * 
     * @param username 用户名
     * @param token    JWT Token
     */
    public void refreshTokenExpiration(String username, String token) {
        if (!redisEnabled || redisTemplate == null) {
            return;
        }
        try {
            String tokenKey = getTokenKey(username, token);
            String userTokensKey = getUserTokensKey(username);

            // 刷新 token 过期时间
            redisTemplate.expire(tokenKey, tokenExpireSeconds, TimeUnit.SECONDS);
            redisTemplate.expire(userTokensKey, tokenExpireSeconds, TimeUnit.SECONDS);

            logger.debug("Token 过期时间已刷新: username={}", username);
        } catch (Exception e) {
            logger.warn("刷新 Token 过期时间失败: username={}, error={}", username, e.getMessage());
        }
    }

    /**
     * 获取用户当前有效的 Token 数量
     * 
     * @param username 用户名
     * @return Token 数量
     */
    public long getTokenCount(String username) {
        if (!redisEnabled || redisTemplate == null) {
            return 0;
        }
        try {
            String userTokensKey = getUserTokensKey(username);
            Long count = redisTemplate.opsForSet().size(userTokensKey);
            return count != null ? count : 0;
        } catch (Exception e) {
            logger.warn("获取用户 Token 数量失败: username={}, error={}", username, e.getMessage());
            return 0;
        }
    }

    /**
     * 检查 Redis 是否可用
     * 
     * @return true 如果 Redis 可用
     */
    public boolean isRedisAvailable() {
        if (!redisEnabled || redisTemplate == null) {
            return false;
        }
        try {
            redisTemplate.opsForValue().get("health_check");
            return true;
        } catch (Exception e) {
            logger.warn("Redis 不可用: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 检查 Redis 是否启用
     */
    public boolean isRedisEnabled() {
        return redisEnabled && redisTemplate != null;
    }

    /**
     * 生成 Token 存储的 key
     */
    private String getTokenKey(String username, String token) {
        // 使用 token 的哈希值作为 key 的一部分，避免 key 过长
        return TOKEN_PREFIX + username + ":" + token.hashCode();
    }

    /**
     * 生成用户 Token 集合的 key
     */
    private String getUserTokensKey(String username) {
        return USER_TOKENS_PREFIX + username;
    }
}
