/**
 * ─────────────────────────────────────────────────────────────────────────────
 * RATE LIMITER — sliding window, in-memory (Redis-ready)
 * ─────────────────────────────────────────────────────────────────────────────
 *
 * Usage:
 *   const limiter = rateLimit({ window: 60_000, max: 5 });
 *   const result  = limiter.check("ip:1.2.3.4");
 *   if (!result.allowed) return 429;
 *
 * To switch to Redis: swap the `store` Map for ioredis/upstash calls.
 */

interface Window {
  count:     number;
  resetTime: number;
}

const store = new Map<string, Window>();

// Cleanup every 5 minutes to prevent memory leaks
if (typeof setInterval !== "undefined") {
  setInterval(() => {
    const now = Date.now();
    for (const [key, win] of store) {
      if (win.resetTime < now) store.delete(key);
    }
  }, 5 * 60 * 1000).unref?.();
}

export interface RateLimitResult {
  allowed:   boolean;
  remaining: number;
  resetIn:   number;  // ms until window resets
}

export function rateLimit(options: {
  window: number;  // window size in ms
  max:    number;  // max requests per window
}) {
  return {
    check(key: string): RateLimitResult {
      const now = Date.now();
      const existing = store.get(key);

      if (!existing || existing.resetTime < now) {
        // New window
        store.set(key, { count: 1, resetTime: now + options.window });
        return { allowed: true, remaining: options.max - 1, resetIn: options.window };
      }

      existing.count++;

      if (existing.count > options.max) {
        return {
          allowed:   false,
          remaining: 0,
          resetIn:   existing.resetTime - now,
        };
      }

      return {
        allowed:   true,
        remaining: options.max - existing.count,
        resetIn:   existing.resetTime - now,
      };
    },

    reset(key: string): void {
      store.delete(key);
    },
  };
}

// ── Pre-configured limiters ───────────────────────────────────────────────────

/** Login: 10 attempts per 15 minutes per IP */
export const loginLimiter = rateLimit({ window: 15 * 60 * 1000, max: 10 });

/** Registration: 5 accounts per hour per IP */
export const registerLimiter = rateLimit({ window: 60 * 60 * 1000, max: 5 });

/** OAuth callbacks: 20 per minute per IP (user may retry) */
export const oauthLimiter = rateLimit({ window: 60 * 1000, max: 20 });

/** General API: 300 requests per minute per clinic */
export const apiLimiter = rateLimit({ window: 60 * 1000, max: 300 });

// ── Helper: extract limiter key from request ──────────────────────────────────
export function getLimiterKey(req: Request, prefix: string): string {
  const ip = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim()
          ?? req.headers.get("x-real-ip")
          ?? "unknown";
  return `${prefix}:${ip}`;
}

// ── Helper: return 429 response with Retry-After ──────────────────────────────
export function tooManyRequests(resetIn: number) {
  const retryAfter = Math.ceil(resetIn / 1000);
  return new Response(
    JSON.stringify({ error: "Too many requests. Please slow down." }),
    {
      status:  429,
      headers: {
        "Content-Type":  "application/json",
        "Retry-After":   String(retryAfter),
        "X-RateLimit-Reset": String(Date.now() + resetIn),
      },
    }
  );
}
