package com.ruoyi.credit.interceptor;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import com.ruoyi.common.utils.StringUtils;

/**
 * API限流拦截器
 * 
 * 实现基于IP地址和用户的API访问频率限制
 * 
 * @author ruoyi
 * @date 2025-12-19
 */
@Component
public class RateLimitInterceptor implements HandlerInterceptor {

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

    @Value("${api.rateLimit.enabled:true}")
    private Boolean rateLimitEnabled;

    @Value("${api.rateLimit.maxRequests:100}")
    private int maxRequests;

    @Value("${api.rateLimit.timeWindow:60}")
    private int timeWindowSeconds;

    // 存储每个IP的请求计数和时间窗口
    private final ConcurrentHashMap<String, RequestCounter> requestCounters = new ConcurrentHashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 安全优先：如果配置未正确加载，默认启用限流
        boolean isRateLimitEnabled = (rateLimitEnabled != null) ? rateLimitEnabled : true;
        
        if (!isRateLimitEnabled) {
            return true;
        }

        String clientIp = getClientIpAddress(request);
        String userId = getUserId(request);
        
        // 使用IP+用户ID作为限流键，如果没有用户ID则只使用IP
        String rateLimitKey = StringUtils.isNotEmpty(userId) ? clientIp + ":" + userId : clientIp;

        if (isRateLimited(rateLimitKey)) {
            logger.warn("API访问频率超限: IP={}, UserId={}, URI={}", clientIp, userId, request.getRequestURI());
            
            response.setStatus(429); // HTTP 429 Too Many Requests
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":429,\"msg\":\"访问频率过高，请稍后再试\"}");
            
            return false;
        }

        return true;
    }

    /**
     * 检查是否超过限流阈值
     */
    private boolean isRateLimited(String key) {
        long currentTime = System.currentTimeMillis();
        long timeWindowMs = timeWindowSeconds * 1000L;

        RequestCounter counter = requestCounters.computeIfAbsent(key, k -> new RequestCounter());

        synchronized (counter) {
            // 如果当前时间超出时间窗口，重置计数器
            if (currentTime - counter.windowStart > timeWindowMs) {
                counter.count.set(0);
                counter.windowStart = currentTime;
            }

            // 增加请求计数
            int currentCount = counter.count.incrementAndGet();
            
            // 检查是否超过限制
            return currentCount > maxRequests;
        }
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (StringUtils.isNotEmpty(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (StringUtils.isNotEmpty(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }

    /**
     * 获取用户ID（从请求头或会话中）
     */
    private String getUserId(HttpServletRequest request) {
        // 尝试从请求头获取用户ID
        String userId = request.getHeader("X-User-Id");
        if (StringUtils.isNotEmpty(userId)) {
            return userId;
        }

        // 尝试从JWT token中解析用户ID（简化处理）
        String authorization = request.getHeader("Authorization");
        if (StringUtils.isNotEmpty(authorization) && authorization.startsWith("Bearer ")) {
            // 这里应该解析JWT token获取用户ID，简化处理
            return "user_from_token";
        }

        return null;
    }

    /**
     * 请求计数器内部类
     */
    private static class RequestCounter {
        private final AtomicInteger count = new AtomicInteger(0);
        private volatile long windowStart = System.currentTimeMillis();
    }

    /**
     * 清理过期的计数器（定期调用）
     */
    public void cleanupExpiredCounters() {
        long currentTime = System.currentTimeMillis();
        long timeWindowMs = timeWindowSeconds * 1000L;

        requestCounters.entrySet().removeIf(entry -> {
            RequestCounter counter = entry.getValue();
            return currentTime - counter.windowStart > timeWindowMs * 2; // 保留2个时间窗口
        });
    }
}