package com.honey.honey.security;

import com.honey.honey.model.UserA;
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 for authenticated user endpoints.
 * Limits requests per user ID to prevent abuse.
 * Requires UserContext to be set (must be applied after AuthInterceptor).
 */
@Slf4j
@Component
public class UserRateLimitInterceptor implements HandlerInterceptor {

    // Rate limit configuration for payment creation
    private static final int MAX_REQUESTS_PER_USER = 5; // per time window
    private static final long TIME_WINDOW_MS = 60_000; // 1 minute

    // User-based rate limiting
    private final Map<Integer, RateLimitEntry> userRateLimit = 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;
        }
        
        // Only rate limit POST requests (GET requests like /api/payouts/history should not be rate limited)
        if (!"POST".equalsIgnoreCase(req.getMethod())) {
            return true;
        }

        // Get user from context (set by AuthInterceptor)
        UserA user = UserContext.get();
        if (user == null) {
            // If no user context, allow (shouldn't happen for authenticated endpoints, but be safe)
            return true;
        }

        Integer userId = user.getId();
        
        // Check user-based rate limit
        if (isRateLimited(userId, userRateLimit, MAX_REQUESTS_PER_USER)) {
            log.warn("Rate limit exceeded: userId={}, endpoint={}", userId, req.getRequestURI());
            res.setStatus(429); // 429 Too Many Requests
            res.setHeader("Retry-After", "60"); // Retry after 60 seconds
            res.setContentType("application/json;charset=UTF-8");
            try {
                java.io.PrintWriter writer = res.getWriter();
                writer.write("{\"message\":\"Too many requests. Please wait a moment before trying again.\"}");
                writer.flush();
            } catch (Exception e) {
                log.error("Error writing rate limit response", e);
            }
            return false;
        }

        return true;
    }

    /**
     * Checks if a user is rate limited.
     */
    private boolean isRateLimited(Integer userId, Map<Integer, RateLimitEntry> rateLimitMap, int maxRequests) {
        long now = System.currentTimeMillis();
        
        RateLimitEntry entry = rateLimitMap.computeIfAbsent(userId, 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<Integer, 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());
    }
}

