import {
  CanActivate,
  ExecutionContext,
  HttpException,
  HttpStatus,
  Injectable,
} from "@nestjs/common";

type RateBucket = {
  count: number;
  resetAt: number;
};

const buckets = new Map<string, RateBucket>();

@Injectable()
export class PublicRateLimitGuard implements CanActivate {
  private readonly windowMs = Number(
    process.env.PUBLIC_RATE_LIMIT_WINDOW_MS || 15 * 60 * 1000,
  );
  private readonly maxRequests = Number(
    process.env.PUBLIC_RATE_LIMIT_MAX || 120,
  );

  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    const now = Date.now();
    const key = this.getClientKey(request);
    const current = buckets.get(key);

    if (!current || current.resetAt <= now) {
      buckets.set(key, { count: 1, resetAt: now + this.windowMs });
      this.cleanup(now);
      return true;
    }

    current.count += 1;

    if (current.count > this.maxRequests) {
      throw new HttpException(
        "Demasiados intentos. Espera unos minutos y vuelve a probar.",
        HttpStatus.TOO_MANY_REQUESTS,
      );
    }

    return true;
  }

  private getClientKey(request: any) {
    const forwardedFor = String(request.headers?.["x-forwarded-for"] || "")
      .split(",")[0]
      .trim();
    return (
      forwardedFor || request.ip || request.socket?.remoteAddress || "unknown"
    );
  }

  private cleanup(now: number) {
    if (buckets.size < 1000) return;

    for (const [key, bucket] of buckets.entries()) {
      if (bucket.resetAt <= now) buckets.delete(key);
    }
  }
}
