/**
response when validation fails:
 * {
 *   "success": false,
 *   "statusCode": 400,
 *   "message": "Bad Request",
 *   "errors": ["email must be an email", "password is too short"],
 *   "timestamp": "2026-05-21T10:00:00.000Z",
 *   "path": "/api/auth/login"
 * }
 */
import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
} from '@nestjs/common';
import { Request, Response } from 'express';

// Shape of the JSON we send back to the client when an error happens.
interface ErrorResponse {
  success: false;
  statusCode: number;
  message: string;
  errors?: string[];
  timestamp: string;
  path: string;
}

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost): void {
    const request = host.switchToHttp().getRequest<Request>();
    const response = host.switchToHttp().getResponse<Response>();

    const statusCode = exception.getStatus();
    const { message, errors } = this.getErrorDetails(exception);

    const errorResponse: ErrorResponse = {
      success: false,
      statusCode,
      message,
      timestamp: new Date().toISOString(),
      path: request.url,
    };

    // Only add `errors` field if there are multiple validation messages.
    if (errors) {
      errorResponse.errors = errors;
    }

    response.status(statusCode).json(errorResponse);
  }
  private getErrorDetails(exception: HttpException): {
    message: string;
    errors?: string[];
  } {
    const payload = exception.getResponse();

    // Case 1: payload is a plain string. Example: "Forbidden"
    if (typeof payload === 'string') {
      return { message: payload };
    }

    const { message, error } = payload as {
      message?: string | string[];
      error?: string;
    };

    // Case 2: message is an array (usually validation errors).
    // Example: message = ["email must be an email", "password too short"]
    if (Array.isArray(message)) {
      return {
        message: error ?? exception.message,
        errors: message,
      };
    }

    // Case 3: message is a single string, or missing.
    return { message: message ?? exception.message };
  }
}
