package org.lingniu.sdk.service;

import lombok.extern.slf4j.Slf4j;
import org.lingniu.sdk.constant.CacheConstants;
import org.lingniu.sdk.model.token.RefreshTokenInfo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class RedisRefreshTokenService {

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisRefreshTokenService(RedisTemplate<String, Object> sdkRedisTemplate) {
        this.redisTemplate = sdkRedisTemplate;
    }

    /**
     * 存储Refresh Token到Redis Hash
     */
    public void storeRefreshToken(RefreshTokenInfo tokenInfo) {
        if (tokenInfo == null || tokenInfo.getTokenValue() == null) {
            log.error("tokenInfo或tokenValue为空");
            return;
        }

        try {
            String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, tokenInfo.getTokenValue());

            // 使用Hash存储token信息
            Map<String, String> tokenMap = tokenInfo.toMap();
            redisTemplate.opsForHash().putAll(key, tokenMap);

            // 设置过期时间
            Instant expiresAt = tokenInfo.getExpiresAt();
            // 30天
            long expireSeconds = 30 * 24 * 3600L;
            if (expiresAt != null) {
                expireSeconds = expiresAt.getEpochSecond() - Instant.now().getEpochSecond();
                if (expireSeconds <= 0) {
                    log.warn("Refresh Token已过期，不再存储: {}", tokenInfo.getTokenValue());
                    redisTemplate.delete(key);
                    return;
                }
            }

            redisTemplate.expire(key, expireSeconds, TimeUnit.SECONDS);
            log.debug("存储Refresh Token成功: key={}, expireSeconds={}", key, expireSeconds);

            // 维护用户会话列表 - 使用Set存储用户的refresh token
            String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, tokenInfo.getUsername());
            redisTemplate.opsForSet().add(userSessionsKey, tokenInfo.getTokenValue());
            redisTemplate.expire(userSessionsKey, expireSeconds, TimeUnit.SECONDS);

        } catch (Exception e) {
            log.error("存储Refresh Token失败: token={}", tokenInfo.getTokenValue(), e);
        }
    }

    /**
     * 获取Refresh Token信息
     */
    public RefreshTokenInfo getRefreshTokenInfo(String token) {
        if (token == null || token.trim().isEmpty()) {
            return null;
        }

        String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
        try {
            // 获取所有hash字段
            Map<Object, Object> entries = redisTemplate.opsForHash().entries(key);
            if (entries.isEmpty()) {
                return null;
            }

            // 转换为Map<String, Object>
            Map<String, Object> cacheMap = convertMap(entries);
            return RefreshTokenInfo.fromMap(cacheMap);

        } catch (Exception e) {
            log.error("获取Refresh Token信息失败: token={}", token, e);
            return null;
        }
    }

    /**
     * 更新Refresh Token最后使用时间
     */
    public void updateRefreshToken(RefreshTokenInfo tokenInfo) {
        if (tokenInfo == null || tokenInfo.getTokenValue() == null) {
            log.error("tokenInfo或tokenValue为空");
            return;
        }

        try {
            String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, tokenInfo.getTokenValue());
            Map<String, String> updateMap = tokenInfo.toUpdateMap();

            // 更新指定字段
            for (Map.Entry<String, String> entry : updateMap.entrySet()) {
                redisTemplate.opsForHash().put(key, entry.getKey(), entry.getValue());
            }

            log.debug("更新Refresh Token成功: token={}", tokenInfo.getTokenValue());

        } catch (Exception e) {
            log.error("更新Refresh Token失败: token={}", tokenInfo.getTokenValue(), e);
        }
    }

    /**
     * 作废/删除Refresh Token
     */
    public void revokeRefreshToken(RefreshTokenInfo tokenInfo) {
        if (tokenInfo == null) {
            log.warn("tokenInfo为空");
            return;
        }

        try {
            String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, tokenInfo.getTokenValue());
            Boolean deleted = redisTemplate.delete(key);

            if (tokenInfo.getUsername() != null) {
                // 从用户会话列表中移除
                String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, tokenInfo.getUsername());
                Long removed = redisTemplate.opsForSet().remove(userSessionsKey, tokenInfo.getTokenValue());
                log.debug("从用户会话列表移除token: user={}, token={}, 移除数量={}",
                        tokenInfo.getUsername(), tokenInfo.getTokenValue(), removed);
            }

            log.debug("作废Refresh Token: token={}, 删除结果={}", tokenInfo.getTokenValue(), deleted);

        } catch (Exception e) {
            log.error("作废Refresh Token失败: token={}", tokenInfo.getTokenValue(), e);
        }
    }

    /**
     * 验证Refresh Token是否存在
     */
    public boolean validateRefreshToken(String token) {
        if (token == null || token.trim().isEmpty()) {
            return false;
        }

        String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            log.error("验证Refresh Token失败: token={}", token, e);
            return false;
        }
    }

    /**
     * 获取用户的所有Refresh Tokens
     */
    public Long getUserRefreshTokensCount(String username) {
        if (username == null || username.trim().isEmpty()) {
            return 0L;
        }

        String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, username);
        try {
            Long size = redisTemplate.opsForSet().size(userSessionsKey);
            return size != null ? size : 0L;
        } catch (Exception e) {
            log.error("获取用户Refresh Tokens数量失败: user={}", username, e);
            return 0L;
        }
    }

    /**
     * 清理用户的所有Refresh Tokens（登出所有设备）
     */
    public Long revokeAllUserRefreshTokens(String username) {
        if (username == null || username.trim().isEmpty()) {
            return 0L;
        }

        try {
            String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, username);

            // 获取用户的所有token
            Set<Object> tokens = redisTemplate.opsForSet().members(userSessionsKey);
            if (tokens == null || tokens.isEmpty()) {
                return 0L;
            }

            long deletedCount = 0;
            for (Object tokenObj : tokens) {
                if (tokenObj instanceof String token) {
                    String tokenKey = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
                    Boolean deleted = redisTemplate.delete(tokenKey);
                    if (deleted) {
                        deletedCount++;
                    }
                }
            }

            // 删除用户会话列表
            redisTemplate.delete(userSessionsKey);

            log.debug("清理用户所有Refresh Tokens: user={}, 清理数量={}", username, deletedCount);
            return deletedCount;

        } catch (Exception e) {
            log.error("清理用户所有Refresh Tokens失败: user={}", username, e);
            return 0L;
        }
    }

    /**
     * 获取Refresh Token剩余生存时间
     */
    public Long getRefreshTokenTtl(String token) {
        if (token == null || token.trim().isEmpty()) {
            return null;
        }

        String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
        try {
            return redisTemplate.getExpire(key, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("获取Refresh Token剩余生存时间失败: token={}", token, e);
            return null;
        }
    }

    /**
     * 刷新Refresh Token过期时间
     */
    public boolean refreshTokenExpire(String token, long expireSeconds) {
        if (token == null || token.trim().isEmpty() || expireSeconds <= 0) {
            return false;
        }

        String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
        try {
            Boolean exists = redisTemplate.hasKey(key);
            if (exists) {
                Boolean refreshed = redisTemplate.expire(key, expireSeconds, TimeUnit.SECONDS);
                log.debug("刷新Refresh Token过期时间: token={}, expireSeconds={}, 结果={}",
                        token, expireSeconds, refreshed);
                return refreshed;
            }
            return false;
        } catch (Exception e) {
            log.error("刷新Refresh Token过期时间失败: token={}", token, e);
            return false;
        }
    }

    /**
     * 辅助方法：转换Map类型
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> convertMap(Map<Object, Object> originalMap) {
        // 根据实际情况转换，这里假设键值都是可序列化的对象
        return (Map<String, Object>) (Map<?, ?>) originalMap;
    }

    /**
     * 检查用户会话列表中是否包含指定token
     */
    public boolean isTokenInUserSessions(String username, String token) {
        if (username == null || token == null) {
            return false;
        }

        String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, username);
        try {
            Boolean isMember = redisTemplate.opsForSet().isMember(userSessionsKey, token);
            return Boolean.TRUE.equals(isMember);
        } catch (Exception e) {
            log.error("检查用户会话列表失败: user={}, token={}", username, token, e);
            return false;
        }
    }
}