/**
 * Simple in-memory sliding-window rate limiter.
 *
 * Each instance tracks requests per key (typically client IP).
 * Old entries are lazily purged on every `check()` call.
 *
 * NOTE: This is per-process. If you run multiple Node workers behind a
 * load-balancer you would need a shared store (Redis, etc.).
 */

interface RateLimitEntry {
  timestamps: number[];
}

export interface RateLimitConfig {
  /** Maximum number of requests allowed within the window. */
  maxRequests: number;
  /** Window size in milliseconds. */
  windowMs: number;
}

export class RateLimiter {
  private store = new Map<string, RateLimitEntry>();
  private readonly maxRequests: number;
  private readonly windowMs: number;

  constructor(config: RateLimitConfig) {
    this.maxRequests = config.maxRequests;
    this.windowMs = config.windowMs;
  }

  /**
   * Check whether the given key is within the rate limit.
   *
   * @returns `true` if the request is allowed, `false` if it should be blocked.
   */
  check(key: string): boolean {
    const now = Date.now();
    const windowStart = now - this.windowMs;

    let entry = this.store.get(key);
    if (!entry) {
      entry = { timestamps: [] };
      this.store.set(key, entry);
    }

    // Remove timestamps outside the current window
    entry.timestamps = entry.timestamps.filter((t) => t > windowStart);

    if (entry.timestamps.length >= this.maxRequests) {
      return false; // rate-limited
    }

    entry.timestamps.push(now);
    return true; // allowed
  }

  /** Periodically call this (or rely on lazy cleanup in `check`). */
  cleanup(): void {
    const now = Date.now();
    const windowStart = now - this.windowMs;

    for (const [key, entry] of this.store) {
      entry.timestamps = entry.timestamps.filter((t) => t > windowStart);
      if (entry.timestamps.length === 0) {
        this.store.delete(key);
      }
    }
  }
}

// ── Pre-configured limiters for specific endpoints ──────────────────────────

/** Contact form: 5 requests per minute per IP */
export const contactLimiter = new RateLimiter({ maxRequests: 5, windowMs: 60_000 });

/** Login: 10 requests per minute per IP */
export const loginLimiter = new RateLimiter({ maxRequests: 10, windowMs: 60_000 });

/** Upload: 20 requests per minute per IP */
export const uploadLimiter = new RateLimiter({ maxRequests: 20, windowMs: 60_000 });

/**
 * Extract a best-effort client IP from the request.
 * In production behind a reverse proxy, `x-forwarded-for` is usually set.
 */
export function getClientIp(req: Request): string {
  const forwarded = req.headers.get("x-forwarded-for");
  if (forwarded) {
    // x-forwarded-for may contain a comma-separated list; first entry is the client
    return forwarded.split(",")[0].trim();
  }
  const realIp = req.headers.get("x-real-ip");
  if (realIp) return realIp.trim();
  return "unknown";
}
