import { configs } from '@/config/configs';
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';
import { Request, Response } from 'express';
import { ZodValidationException } from 'nestjs-zod';

@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>();

    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let message: any = 'Internal server error';
    let errorDetails = null;
    let code: string | undefined;
    let data: unknown;

    if (exception instanceof ZodValidationException) {
      status = 422;
      const zodError = exception.getZodError() as any;
      message = exception.message;
      errorDetails = JSON.parse(zodError.message)?.map((issue: any) => {
        return {
          field: issue.path.join('.'),
          expected: issue.expected,
          message: issue.message,
        };
      });
    } else if (exception instanceof HttpException) {
      status = exception.getStatus();
      const resContent = exception.getResponse();
      if (typeof resContent === 'object' && resContent !== null) {
        message = (resContent as any).message || message;
        errorDetails = (resContent as any).error || null;
        // Allow handlers/guards to surface a machine-readable code + payload (e.g. feature_disabled)
        code = (resContent as any).code;
        data = (resContent as any).data;
      } else {
        message = resContent;
      }
    } else if (exception instanceof Error) {
      message = exception.message;
    }

    const isDevEnv = configs().app.env == 'development';
    response.status(status).json({
      status: false,
      statusCode: status,
      path: isDevEnv ? request.url : undefined,
      code,
      message: Array.isArray(message) ? message[0] : message, // Standardizes class-validator array messages if present
      error: errorDetails,
      data,
    });
  }
}
