import {
  ExceptionFilter,
  Catch,
  ArgumentsHost,
  HttpException,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { DomainException } from '../exceptions/domain.exception';
import { ApplicationException } from '../exceptions/application.exception';

interface ErrorResponse {
  statusCode: number;
  timestamp: string;
  path: string;
  method: string;
  message: string;
  error: string;
  details?: unknown;
}

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

  catch(exception: unknown, host: ArgumentsHost): void {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse<Response>();
    const request = ctx.getRequest<Request>();

    const errorResponse = this.buildErrorResponse(exception, request);

    // 记录日志
    this.logException(exception, errorResponse);

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

  private buildErrorResponse(
    exception: unknown,
    request: Request,
  ): ErrorResponse {
    const timestamp = new Date().toISOString();
    const path = request.url;
    const method = request.method;

    // 处理 HTTP 异常
    if (exception instanceof HttpException) {
      const status = exception.getStatus();
      const exceptionResponse = exception.getResponse();

      return {
        statusCode: status,
        timestamp,
        path,
        method,
        message: this.extractMessage(exceptionResponse),
        error: HttpStatus[status] || 'Unknown Error',
        details: this.extractDetails(exceptionResponse),
      };
    }

    // 处理领域异常 (业务规则违反)
    if (exception instanceof DomainException) {
      return {
        statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
        timestamp,
        path,
        method,
        message: exception.message,
        error: 'Domain Error',
      };
    }

    // 处理应用异常 (应用层错误)
    if (exception instanceof ApplicationException) {
      return {
        statusCode: HttpStatus.BAD_REQUEST,
        timestamp,
        path,
        method,
        message: exception.message,
        error: 'Application Error',
      };
    }

    // 处理未知异常
    const message =
      exception instanceof Error ? exception.message : 'Internal server error';

    return {
      statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
      timestamp,
      path,
      method,
      message:
        process.env.NODE_ENV === 'production'
          ? 'Internal server error'
          : message,
      error: 'Internal Server Error',
    };
  }

  private extractMessage(response: string | object): string {
    if (typeof response === 'string') {
      return response;
    }

    if (typeof response === 'object' && response !== null) {
      const responseObj = response as Record<string, unknown>;
      if (typeof responseObj.message === 'string') {
        return responseObj.message;
      }
      if (Array.isArray(responseObj.message)) {
        return responseObj.message[0] || 'Validation failed';
      }
    }

    return 'Unknown error';
  }

  private extractDetails(response: string | object): unknown | undefined {
    if (typeof response === 'object' && response !== null) {
      const responseObj = response as Record<string, unknown>;
      if (Array.isArray(responseObj.message) && responseObj.message.length > 1) {
        return { validationErrors: responseObj.message };
      }
    }
    return undefined;
  }

  private logException(exception: unknown, errorResponse: ErrorResponse): void {
    const { statusCode, path, method, message } = errorResponse;

    const logContext = {
      statusCode,
      path,
      method,
      message,
    };

    if (statusCode >= 500) {
      // 服务器错误 - 记录完整堆栈
      this.logger.error(
        `[${method}] ${path} - ${statusCode} - ${message}`,
        exception instanceof Error ? exception.stack : undefined,
        logContext,
      );
    } else if (statusCode >= 400) {
      // 客户端错误 - 警告级别
      this.logger.warn(`[${method}] ${path} - ${statusCode} - ${message}`);
    }
  }
}
