import { rateLimit, type RateLimitRequestHandler } from "express-rate-limit";
import type { Request, Response } from "express";

const isProduction = process.env.NODE_ENV === "production";

function envInt(name: string, fallback: number): number {
  const raw = process.env[name];
  if (raw == null || raw === "") return fallback;
  const n = Number(raw);
  return Number.isFinite(n) && n > 0 ? Math.floor(n) : fallback;
}

function isLoopback(ip: string | undefined): boolean {
  if (!ip) return false;
  if (ip === "127.0.0.1" || ip === "::1") return true;
  if (ip.startsWith("::ffff:127.")) return true;
  return false;
}

function skipForLocalDev(req: Request): boolean {
  if (isProduction) return false;
  if (process.env.SETUP_RATE_LIMIT_FORCE === "1") return false;
  return isLoopback(req.ip);
}

function jsonHandler(_req: Request, res: Response): void {
  res.status(429).json({
    error: "too_many_requests",
    message: "Too many setup attempts. Please slow down and try again later.",
  });
}

// Stricter than the generic auth limiter — first-time setup is a one-shot
// flow, so we cap any single IP to a small handful of POSTs per window.
// Applied only to /setup/validate and /setup/complete (mutation endpoints).
export const setupRateLimit: RateLimitRequestHandler = rateLimit({
  windowMs: envInt("SETUP_RATE_LIMIT_WINDOW_MS", 15 * 60_000),
  max: envInt("SETUP_RATE_LIMIT_MAX", 10),
  standardHeaders: true,
  legacyHeaders: false,
  skip: skipForLocalDev,
  handler: jsonHandler,
});

// Looser limiter for GET /setup/status. The SPA polls this on every
// route change to decide whether to redirect to the wizard, so it
// must tolerate normal user navigation without locking anyone out.
export const setupStatusRateLimit: RateLimitRequestHandler = rateLimit({
  windowMs: envInt("SETUP_STATUS_RATE_LIMIT_WINDOW_MS", 60_000),
  max: envInt("SETUP_STATUS_RATE_LIMIT_MAX", 120),
  standardHeaders: true,
  legacyHeaders: false,
  skip: skipForLocalDev,
  handler: jsonHandler,
});
