import {
  Injectable,
  type CallHandler,
  type ExecutionContext,
  type NestInterceptor,
} from '@nestjs/common';
import { type Request, type Response } from 'express';
import { type Observable, tap } from 'rxjs';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
import { MetricsService } from '../../infrastructure/metrics.service';

@Injectable()
export class HttpMetricsInterceptor implements NestInterceptor {
  constructor(private readonly metricsService: MetricsService) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
    const httpContext = context.switchToHttp();
    const request = httpContext.getRequest<Request>();
    const startTime = process.hrtime.bigint();

    return next.handle().pipe(
      tap({
        next: () => {
          this.recordMetrics(request, httpContext.getResponse<Response>(), startTime);
        },
        error: () => {
          this.recordMetrics(request, httpContext.getResponse<Response>(), startTime);
        },
      }),
    );
  }

  private recordMetrics(
    request: Request,
    response: Response,
    startTime: bigint,
  ): void {
    const durationNs = Number(process.hrtime.bigint() - startTime);
    const durationSeconds = durationNs / 1e9;

    const route = (request.route as { path?: string })?.path ?? request.path;
    const method = request.method;
    const statusCode = response.statusCode;

    this.metricsService.recordHttpRequest(method, route, statusCode, durationSeconds);
  }
}
