package org.lingniu.idp.service.core.login;

import lombok.extern.slf4j.Slf4j;
import org.lingniu.idp.common.redis.RedisCache;
import org.lingniu.idp.constant.CacheConstants;
import org.lingniu.idp.constant.Constants;
import org.springframework.beans.factory.annotation.Autowired;
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 SecurityEnhancer {
    
    @Autowired
    private RedisCache redisCache;
    
    private final int MAX_SESSIONS_PER_USER = 5;
    
    /**
     * 会话管理 - 限制每个用户的最大会话数
     */
    public void enforceSessionLimit(String userId) {
        String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, userId);
        Set<Object> sessions = redisCache.getCacheSet(userSessionsKey);
        
        if (sessions != null && sessions.size() >= MAX_SESSIONS_PER_USER) {
            // 移除最旧的会话
            removeOldestSession(userId, sessions);
        }
    }
    
    private void removeOldestSession(String userId, Set<Object> sessions) {
        String oldestSession = null;
        Instant oldestTime = Instant.MAX;
        
        for (Object sessionToken : sessions) {
            String token = (String) sessionToken;
            String refreshTokenKey = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
            Map<String, Object> hash = redisCache.getCacheMap(refreshTokenKey);
            
            if (hash.containsKey("lastUsedAt")) {
                Instant lastUsedAt = Instant.parse((String) hash.get("lastUsedAt"));
                if (lastUsedAt.isBefore(oldestTime)) {
                    oldestTime = lastUsedAt;
                    oldestSession = token;
                }
            }
        }
        
        if (oldestSession != null) {
            revokeToken(oldestSession, "refresh_token");
            log.info("用户{}超出会话限制，移除最旧会话: {}", userId, oldestSession);
        }
    }
    
    /**
     * Token撤销机制
     */
    public void revokeToken(String token, String tokenType) {
        if ("access_token".equals(tokenType)) {
            String key = String.format(CacheConstants.ACCESS_TOKEN_KEY, token);
            redisCache.deleteObject(key);
            log.info("撤销Access Token: {}", token);
        } else if ("refresh_token".equals(tokenType)) {
            String key = String.format(CacheConstants.REFRESH_TOKEN_KEY, token);
            
            // 获取用户ID，从用户会话列表中移除
            Map<String, Object> hash = redisCache.getCacheMap(key);
            if (hash.containsKey("userId")) {
                String userId = (String) hash.get("userId");
                String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, userId);
                redisCache.deleteCacheSetValue(userSessionsKey,token);
            }

            redisCache.deleteObject(key);
            log.info("撤销Refresh Token: {}", token);
        }
    }
    
    /**
     * 设备指纹验证
     */
    public boolean validateDeviceFingerprint(String userId, String deviceId, String deviceFingerprint) {
        if (deviceId == null || deviceFingerprint == null) {
            return true; // 如果设备信息为空，允许通过（可能是首次登录）
        }
        
        String deviceKey = String.format("device_fingerprint:%s:%s", userId, deviceId);
        String storedFingerprint = redisCache.getCacheObject(deviceKey);
        
        if (storedFingerprint == null) {
            // 首次使用该设备，存储指纹
            redisCache.setCacheObject(deviceKey,deviceFingerprint);
            redisCache.expire(deviceKey,30, TimeUnit.DAYS);
            return true;
        }
        
        return deviceFingerprint.equals(storedFingerprint);
    }
    
    /**
     * 强制用户下线
     */
    public void forceLogout(String userId) {
        String userSessionsKey = String.format(CacheConstants.USER_SESSIONS, userId);
        Set<Object> sessions = redisCache.getCacheSet(userSessionsKey);
        
        if (sessions != null) {
            for (Object sessionToken : sessions) {
                revokeToken((String) sessionToken, "refresh_token");
            }
        }
        
        log.info("强制用户{}下线，清除所有会话", userId);
    }
    
    /**
     * 检查token是否在黑名单中
     */
    public boolean isTokenBlacklisted(String token) {
        String key = "token_blacklist:" + token;
        return Boolean.TRUE.equals(redisCache.hasKey(key));
    }
    
    /**
     * 将token加入黑名单
     */
    public void blacklistToken(String token, long expireSeconds) {
        String key = "token_blacklist:" + token;
        redisCache.setCacheObject(key,"1");
        redisCache.expire(key,expireSeconds,TimeUnit.SECONDS);
    }
}