import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
} from '@nestjs/common';
import { Request, Response } from 'express';

/**
 * HTTP 예외 필터
 *
 * @description
 * 모든 HTTP 예외를 잡아서 일관된 형식으로 응답을 반환합니다.
 *
 * @example
 * // main.ts에서 전역 적용
 * app.useGlobalFilters(new HttpExceptionFilter());
 *
 * @export
 * @class HttpExceptionFilter
 * @implements {ExceptionFilter}
 */
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();
    const status = exception.getStatus();
    const exceptionResponse = exception.getResponse();

    // 에러 메시지 추출
    let message: string | string[];
    if (typeof exceptionResponse === 'string') {
      message = exceptionResponse;
    } else if (typeof exceptionResponse === 'object' && exceptionResponse !== null) {
      message = (exceptionResponse as any).message || exception.message;
    } else {
      message = exception.message;
    }

    // 일관된 에러 응답 형식
    const errorResponse = {
      success: false,
      statusCode: status,
      timestamp: new Date().toISOString(),
      path: request.url,
      method: request.method,
      message: Array.isArray(message) ? message : [message],
      error: this.getErrorName(status),
    };

    // 개발 환경에서는 스택 트레이스 포함
    if (process.env.NODE_ENV === 'development') {
      (errorResponse as any).stack = exception.stack;
    }

    // 로깅
    console.error(
      `[${errorResponse.timestamp}] ${request.method} ${request.url} - ${status}`,
      message,
    );

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

  /**
   * HTTP 상태 코드에 따른 에러 이름 반환
   *
   * @private
   * @param {number} status - HTTP 상태 코드
   * @returns {string}
   */
  private getErrorName(status: number): string {
    switch (status) {
      case HttpStatus.BAD_REQUEST:
        return 'Bad Request';
      case HttpStatus.UNAUTHORIZED:
        return 'Unauthorized';
      case HttpStatus.FORBIDDEN:
        return 'Forbidden';
      case HttpStatus.NOT_FOUND:
        return 'Not Found';
      case HttpStatus.CONFLICT:
        return 'Conflict';
      case HttpStatus.INTERNAL_SERVER_ERROR:
        return 'Internal Server Error';
      default:
        return 'Error';
    }
  }
}
