package com.honey.honey.security;

import com.honey.honey.util.IpUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

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

/**
 * Rate limiting interceptor (IP-based). Limits requests per IP to prevent abuse.
 * Note: Not currently registered for any path in WebConfig; available if needed.
 */
@Slf4j
@Component
public class RateLimitInterceptor implements HandlerInterceptor {

    // Rate limit configuration
    private static final int MAX_REQUESTS_PER_IP = 10; // per time window
    private static final long TIME_WINDOW_MS = 60_000; // 1 minute

    // IP-based rate limiting
    private final Map<String, RateLimitEntry> ipRateLimit = new ConcurrentHashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
        // Allow CORS preflight (OPTIONS) without rate limiting
        if ("OPTIONS".equalsIgnoreCase(req.getMethod())) {
            return true;
        }

        String clientIp = IpUtils.getClientIp(req);
        
        if (clientIp == null) {
            // If we can't determine IP, allow the request (shouldn't happen, but be safe)
            return true;
        }
        
        // Check IP-based rate limit
        if (isRateLimited(clientIp, ipRateLimit, MAX_REQUESTS_PER_IP)) {
            log.warn("Rate limit exceeded for bot registration - IP={}, maxRequests={}, window={}ms", 
                    clientIp, MAX_REQUESTS_PER_IP, TIME_WINDOW_MS);
            res.setStatus(429); // 429 Too Many Requests
            res.setHeader("Retry-After", "60"); // Retry after 60 seconds
            return false;
        }

        return true;
    }

    /**
     * Checks if a key is rate limited.
     */
    private boolean isRateLimited(String key, Map<String, RateLimitEntry> rateLimitMap, int maxRequests) {
        long now = System.currentTimeMillis();
        
        RateLimitEntry entry = rateLimitMap.computeIfAbsent(key, k -> new RateLimitEntry());
        
        // Reset if time window has passed
        if (now - entry.windowStart.get() > TIME_WINDOW_MS) {
            entry.count.set(0);
            entry.windowStart.set(now);
        }
        
        // Increment and check
        int currentCount = entry.count.incrementAndGet();
        
        // Clean up old entries periodically
        if (currentCount == 1 && rateLimitMap.size() > 1000) {
            cleanupOldEntries(rateLimitMap, now);
        }
        
        return currentCount > maxRequests;
    }

    /**
     * Cleans up old rate limit entries.
     */
    private void cleanupOldEntries(Map<String, RateLimitEntry> rateLimitMap, long now) {
        rateLimitMap.entrySet().removeIf(entry -> 
            now - entry.getValue().windowStart.get() > TIME_WINDOW_MS * 2
        );
    }

    /**
     * Rate limit entry for tracking requests.
     */
    private static class RateLimitEntry {
        final AtomicInteger count = new AtomicInteger(0);
        final AtomicLong windowStart = new AtomicLong(System.currentTimeMillis());
    }
}

