import {
  CallHandler,
  ExecutionContext,
  Injectable,
  Logger,
  NestInterceptor,
} from "@nestjs/common";
import { Observable, tap, catchError, throwError } from "rxjs";

@Injectable()
export class SecurityInterceptor implements NestInterceptor {
  private readonly logger = new Logger("Security");

  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
    const request = context.switchToHttp().getRequest<{
      method: string;
      url: string;
      ip: string;
      headers: Record<string, string>;
      tenantId?: string;
    }>();
    const response = context.switchToHttp().getResponse<{ statusCode: number }>();

    const ip =
      request.headers["x-forwarded-for"]?.split(",")[0]?.trim() ||
      request.ip ||
      "unknown";

    const { method, url } = request;
    const startTime = Date.now();

    return next.handle().pipe(
      tap(() => {
        const status = response.statusCode;
        const duration = Date.now() - startTime;

        // Log suspicious 4xx responses (excluding 404 for noise reduction)
        if (status >= 400 && status !== 404) {
          this.logger.warn(
            `[${status}] ${method} ${url} | IP: ${ip} | Tenant: ${request.tenantId ?? "none"} | ${duration}ms`,
          );
        }

        // Log slow requests (potential timing attacks or abuse)
        if (duration > 5000) {
          this.logger.warn(
            `[SLOW] ${method} ${url} | IP: ${ip} | ${duration}ms`,
          );
        }
      }),
      catchError((err: Error & { status?: number }) => {
        const status = err.status ?? 500;
        const duration = Date.now() - startTime;

        if (status === 401 || status === 403) {
          this.logger.warn(
            `[${status} UNAUTHORIZED] ${method} ${url} | IP: ${ip} | Tenant: ${request.tenantId ?? "none"} | ${duration}ms`,
          );
        } else if (status === 429) {
          this.logger.warn(
            `[429 RATE_LIMITED] ${method} ${url} | IP: ${ip} | ${duration}ms`,
          );
        } else if (status >= 500) {
          this.logger.error(
            `[${status} SERVER_ERROR] ${method} ${url} | IP: ${ip} | Error: ${err.message}`,
          );
        }

        return throwError(() => err);
      }),
    );
  }
}
