package com.davos.assessment.config;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

@Component
public class AuthRateLimitFilter extends OncePerRequestFilter {
  private final int maxAttempts;
  private final long windowSeconds;
  private final Map<String, Bucket> buckets = new ConcurrentHashMap<>();

  public AuthRateLimitFilter(
      @Value("${app.auth-rate-limit.max-attempts:2000}") int maxAttempts,
      @Value("${app.auth-rate-limit.window-seconds:300}") long windowSeconds) {
    this.maxAttempts = maxAttempts;
    this.windowSeconds = windowSeconds;
  }

  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {
    if (!isAuthWrite(request)) {
      filterChain.doFilter(request, response);
      return;
    }

    String key = clientIp(request) + ":" + request.getRequestURI();
    Bucket bucket = buckets.compute(key, (ignored, current) -> {
      long now = Instant.now().getEpochSecond();
      if (current == null || now - current.windowStart > windowSeconds) {
        return new Bucket(now, 1);
      }
      current.count++;
      return current;
    });

    if (bucket.count > maxAttempts) {
      response.setStatus(429);
      response.setContentType("application/json;charset=UTF-8");
      response.getWriter().write("{\"message\":\"请求过于频繁，请稍后再试\"}");
      return;
    }

    filterChain.doFilter(request, response);
  }

  private boolean isAuthWrite(HttpServletRequest request) {
    String uri = request.getRequestURI();
    return "POST".equalsIgnoreCase(request.getMethod())
        && ("/api/auth/login".equals(uri)
        || "/api/auth/register".equals(uri)
        || uri.matches("^/api/projects/[^/]+/auth/(register|join)$"));
  }

  private String clientIp(HttpServletRequest request) {
    String forwarded = request.getHeader("X-Forwarded-For");
    if (forwarded != null && !forwarded.isBlank()) {
      return forwarded.split(",")[0].trim();
    }
    return request.getRemoteAddr();
  }

  private static class Bucket {
    private final long windowStart;
    private int count;

    private Bucket(long windowStart, int count) {
      this.windowStart = windowStart;
      this.count = count;
    }
  }
}
