import { Injectable } from '@nestjs/common';
import { CallHandler, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

/**
 * ResponseTimeInterceptor - Measures and logs HTTP request response times
 *
 * This interceptor calculates the duration of HTTP requests and logs them to the console.
 * It's useful for performance monitoring, debugging slow endpoints, and identifying
 * potential bottlenecks in your application.
 *
 * @example
 * // Apply globally to all routes
 * app.useGlobalInterceptors(new ResponseTimeInterceptor());
 *
 * // Or apply to specific controller/route
 * @UseInterceptors(ResponseTimeInterceptor)
 * @Controller('api')
 * export class ApiController {}
 */
@Injectable()
export class ResponseTimeInterceptor {
  /**
   * Intercepts HTTP requests to measure and log their response time
   *
   * @param context - ExecutionContext containing request/response details
   * @param next - CallHandler to proceed with the request processing
   * @returns Observable that processes the request and logs the response time
   *
   * @note The timing starts when the interceptor is called and ends when the response is complete
   * @note This includes middleware, guards, interceptors, handler execution, and response serialization
   */
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    // Capture the start time immediately when the request enters the interceptor
    // Using Date.now() for simplicity, but consider performance.now() for higher precision
    const start = Date.now();

    // Continue processing the request through the NestJS pipeline
    return next.handle().pipe(
      // Use the tap operator to execute side effects without modifying the response
      tap(() => {
        // Calculate the total duration in milliseconds
        const duration = Date.now() - start;

        // Extract the HTTP request object to get route information
        const request = context.switchToHttp().getRequest();

        // Log the request URL and response time
        // Consider using a structured logger (e.g., Winston, Pino) in production
        console.log(`Request to ${request.originalUrl} took ${duration}ms`);
      }),
    );
  }
}

/**
 * Usage Notes and Best Practices:
 *
 * 1. **Performance Impact**: This interceptor adds minimal overhead (~0.1-0.5ms per request)
 *    but should be disabled in production if not needed for monitoring.
 *
 * 2. **Logging Strategy**:
 *    - For production, integrate with a structured logging system
 *    - Consider adding log levels (INFO for normal, WARN for slow requests)
 *    - Add request ID correlation for distributed tracing
 *
 * 3. **Enhanced Version Example**:
 *
 *   ```typescript
 *   tap(() => {
 *     const duration = Date.now() - start;
 *     const request = context.switchToHttp().getRequest();
 *     const response = context.switchToHttp().getResponse();
 *
 *     // Log with structured format
 *     logger.log({
 *       message: 'Request completed',
 *       url: request.originalUrl,
 *       method: request.method,
 *       statusCode: response.statusCode,
 *       duration: `${duration}ms`,
 *       timestamp: new Date().toISOString(),
 *       userId: request.user?.id, // If using authentication
 *     });
 *
 *     // Optional: Log slow requests as warnings
 *     if (duration > 1000) {
 *       logger.warn(`Slow request detected: ${request.originalUrl} took ${duration}ms`);
 *     }
 *   })
 *   ```
 *
 * 4. **Integration with Monitoring**:
 *    - Export metrics to Prometheus/Grafana
 *    - Send to APM tools like New Relic, DataDog, or Elastic APM
 *    - Set up alerts for response time thresholds
 *
 * 5. **Testing Considerations**:
 *    - Mock the console.log in unit tests
 *    - Verify timing doesn't affect request/response content
 *    - Test with async operations to ensure accurate timing
 */
