import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { FastifyReply, FastifyRequest } from 'fastify';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  private readonly logger = new Logger(HttpExceptionFilter.name);

  catch(exception: HttpException, host: ArgumentsHost) {
    try {
      const ctx = host.switchToHttp();
      const reply = ctx.getResponse<FastifyReply>();
      const request = ctx.getRequest<FastifyRequest>();

      if (!reply || typeof reply.status !== 'function') {
        return;
      }

      const status = exception.getStatus() || HttpStatus.INTERNAL_SERVER_ERROR;
      const exceptionResponse = exception.getResponse();
      const message = this.extractMessage(exceptionResponse);

      this.logError(exception, request, status, message);

      reply.status(status).send({
        statusCode: status,
        success: false,
        error: { message },
      });
    } catch {
      return;
    }
  }

  private logError(
    exception: HttpException,
    request: FastifyRequest,
    status: number,
    message: string | string[],
  ) {
    const logContext = {
      statusCode: status,
      method: request.method,
      url: request.url,
      ip: request.ip,
      message,
    };

    if (status >= HttpStatus.INTERNAL_SERVER_ERROR) {
      this.logger.error(
        `[${request.method}] ${request.url} → ${status}`,
        exception.stack,
        JSON.stringify(logContext),
      );
    } else {
      this.logger.warn(
        `[${request.method}] ${request.url} → ${status}`,
        JSON.stringify(logContext),
      );
    }
  }

  private extractMessage(response: string | Record<string, any>): string | string[] {
    if (typeof response === 'string') {
      return [response];
    }
    if (typeof response === 'object' && 'message' in response) {
      return Array.isArray(response.message) ? response.message : [response.message];
    }

    return 'something wrong';
  }
}
