import type { NextFunction, Request, Response } from 'express';

interface Bucket {
  count: number;
  resetsAt: number;
}

export const createRateLimit = (options: {
  windowMs: number;
  maxRequests: number;
  message: string;
}) => {
  const buckets = new Map<string, Bucket>();
  const cleanup = setInterval(() => {
    const now = Date.now();
    for (const [key, bucket] of buckets) {
      if (bucket.resetsAt <= now) buckets.delete(key);
    }
  }, Math.min(options.windowMs, 60_000));
  cleanup.unref();

  return (request: Request, response: Response, next: NextFunction): void => {
    const now = Date.now();
    const key = `${request.ip}:${request.path}`;
    const current = buckets.get(key);
    const bucket = !current || current.resetsAt <= now
      ? { count: 0, resetsAt: now + options.windowMs }
      : current;
    bucket.count += 1;
    buckets.set(key, bucket);
    response.setHeader('RateLimit-Limit', options.maxRequests);
    response.setHeader('RateLimit-Remaining', Math.max(0, options.maxRequests - bucket.count));
    response.setHeader('RateLimit-Reset', Math.ceil(bucket.resetsAt / 1000));
    if (bucket.count > options.maxRequests) {
      response.setHeader('Retry-After', Math.ceil((bucket.resetsAt - now) / 1000));
      response.status(429).json({ error: options.message });
      return;
    }
    next();
  };
};
