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

// In-memory rate limiter for login endpoint
// Key: IP address | Value: { count, firstAttempt }
const loginAttempts = new Map<string, { count: number; firstAttemptAt: number }>();

const MAX_ATTEMPTS = 5;
const WINDOW_MS = 15 * 60 * 1000; // 15 minutes

// Clean up expired entries every 5 minutes
setInterval(() => {
  const now = Date.now();
  for (const [key, entry] of loginAttempts.entries()) {
    if (now - entry.firstAttemptAt > WINDOW_MS) {
      loginAttempts.delete(key);
    }
  }
}, 5 * 60 * 1000);

@Injectable()
export class LoginRateLimitGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest<{
      ip: string;
      headers: Record<string, string>;
    }>();

    // Trust X-Forwarded-For in production (behind reverse proxy)
    const ip =
      request.headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
      request.ip ||
      "unknown";

    // Em ambiente de desenvolvimento / localhost, desativa o bloqueio por IP
    if (
      process.env.NODE_ENV !== "production" ||
      ip === "::1" ||
      ip === "127.0.0.1" ||
      ip === "::ffff:127.0.0.1" ||
      ip === "unknown"
    ) {
      loginAttempts.delete(ip);
      return true;
    }

    const now = Date.now();
    const entry = loginAttempts.get(ip);

    if (entry) {
      const windowExpired = now - entry.firstAttemptAt > WINDOW_MS;
      if (windowExpired) {
        // Reset window
        loginAttempts.set(ip, { count: 1, firstAttemptAt: now });
        return true;
      }

      if (entry.count >= MAX_ATTEMPTS) {
        const retryAfterSeconds = Math.ceil((WINDOW_MS - (now - entry.firstAttemptAt)) / 1000);
        throw new HttpException(
          {
            statusCode: HttpStatus.TOO_MANY_REQUESTS,
            error: "Too Many Requests",
            message: `Muitas tentativas de login. Tente novamente em ${Math.ceil(retryAfterSeconds / 60)} minutos.`,
            retryAfter: retryAfterSeconds,
          },
          HttpStatus.TOO_MANY_REQUESTS,
        );
      }

      entry.count += 1;
    } else {
      loginAttempts.set(ip, { count: 1, firstAttemptAt: now });
    }

    return true;
  }
}

/** Call this after a successful login to clear the rate limit record for that IP */
export function clearLoginAttempts(ip: string): void {
  loginAttempts.delete(ip);
}
