import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import type { Response } from 'express';
import type { ApiResponse } from './api-response.type';

type ExceptionResponseBody = {
  message?: string | string[];
  msg?: string;
  error?: string;
};

@Catch()
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: unknown, host: ArgumentsHost) {
    const response = host.switchToHttp().getResponse<Response>();
    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    response.status(status).json({
      code: status,
      data: null,
      msg: this.getMessage(exception),
    } satisfies ApiResponse<null>);
  }

  private getMessage(exception: unknown) {
    if (exception instanceof HttpException) {
      const exceptionResponse = exception.getResponse();

      if (typeof exceptionResponse === 'string') {
        return exceptionResponse;
      }

      if (this.isExceptionResponseBody(exceptionResponse)) {
        const message =
          exceptionResponse.msg ||
          exceptionResponse.message ||
          exceptionResponse.error;

        if (Array.isArray(message)) {
          return message.join('; ');
        }

        if (message) {
          return message;
        }
      }

      return exception.message;
    }

    if (exception instanceof Error && exception.message) {
      return exception.message;
    }

    return 'Internal server error';
  }

  private isExceptionResponseBody(value: unknown): value is ExceptionResponseBody {
    return Boolean(value && typeof value === 'object');
  }
}
