import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from "@nestjs/common";
import type { Request, Response } from "express";
import { randomUUID } from "crypto";

interface ErrorResponse {
  success: false;
  message: string;
  errorId: string;
  timestamp: string;
  path: string;
  statusCode: number;
}

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

    const errorId = randomUUID();
    const timestamp = new Date().toISOString();

    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message = "An unexpected error occurred";

    if (exception instanceof HttpException) {
      status = exception.getStatus();
      const exceptionResponse = exception.getResponse();
      message =
        typeof exceptionResponse === "string"
          ? exceptionResponse
          : ((exceptionResponse as { message?: string }).message ?? message);
    } else if (exception instanceof Error) {
      message = exception.message;
    }

    const isProduction = process.env.NODE_ENV === "production";

    // Structured error logging
    const logPayload = {
      level: "error",
      errorId,
      timestamp,
      method: request.method,
      url: request.url,
      statusCode: status,
      message: exception instanceof Error ? exception.message : String(exception),
      stack: !isProduction && exception instanceof Error ? exception.stack : undefined,
    };

    console.error(isProduction ? JSON.stringify(logPayload) : logPayload);

    // Sanitized client response
    const errorResponse: ErrorResponse = {
      success: false,
      message:
        isProduction && status === HttpStatus.INTERNAL_SERVER_ERROR
          ? "An unexpected error occurred"
          : message,
      errorId,
      timestamp,
      path: request.url,
      statusCode: status,
    };

    response.status(status).json(errorResponse);
  }
}
