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

/**
 * 统一错误响应格式
 */
export interface ApiErrorResponse {
  success: false;
  error: {
    code: string;
    message: string;
    details?: any;
    field?: string;
    errors?: FieldError[];
    stack?: string;
  };
  timestamp: string;
  path: string;
  method: string;
  statusCode: number;
}

/**
 * 字段验证错误
 */
export interface FieldError {
  field: string;
  message: string;
  value?: any;
  constraint?: string;
}

/**
 * 全局异常过滤器
 * 
 * 统一处理所有异常，返回标准错误格式：
 * {
 *   success: false,
 *   error: {
 *     code: string,
 *     message: string,
 *     details?: any,
 *     errors?: FieldError[]
 *   },
 *   timestamp: string,
 *   path: string,
 *   method: string,
 *   statusCode: number
 * }
 * 
 * 使用方式：
 * 在 main.ts 中 app.useGlobalFilters(new AllExceptionsFilter())
 */
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
  private readonly logger = new Logger(AllExceptionsFilter.name);

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

    // ⚠️ SSE 请求特殊处理：如果响应已经开始发送，不能再设置 headers
    const isSSE = request.headers.accept?.includes('text/event-stream');
    const headersSent = response.headersSent;
    
    if (isSSE || headersSent) {
      // SSE 请求或响应已发送，只记录错误，不尝试设置 headers
      this.logger.error(
        `SSE/Stream error: ${request.method} ${request.url}`,
        exception instanceof Error ? exception.stack : JSON.stringify(exception),
      );
      // 不进行任何响应操作，让 Observable 流处理错误
      return;
    }

    let status = HttpStatus.INTERNAL_SERVER_ERROR;
    let errorCode = 'INTERNAL_SERVER_ERROR';
    let message = '服务器内部错误';
    let details: any = undefined;
    let errors: any[] | undefined = undefined;

    // HTTP 异常
    if (exception instanceof HttpException) {
      status = exception.getStatus();
      const exceptionResponse = exception.getResponse();
      
      if (typeof exceptionResponse === 'object') {
        const response = exceptionResponse as any;

        // 获取错误消息
        message = response.message || exception.message;
        if (Array.isArray(message)) {
          // class-validator 返回的是数组
          errors = message;
          message = '请求参数验证失败';
        }

        // 获取错误代码
        errorCode = response.error || response.code || this.getErrorCode(status);

        // 获取详细信息（保留所有自定义字段）
        details = response.details;
        
        // 将所有自定义字段添加到 details 中
        const customFields: Record<string, any> = {};
        const standardFields = ['message', 'error', 'code', 'statusCode', 'details'];
        for (const key in response) {
          if (!standardFields.includes(key) && response[key] !== undefined) {
            customFields[key] = response[key];
          }
        }
        
        // 如果有自定义字段，合并到 details
        if (Object.keys(customFields).length > 0) {
          details = { ...(details && typeof details === 'object' ? details : {}), ...customFields };
        }

        // 处理验证错误
        if (errors && errors.length > 0) {
          errorCode = 'VALIDATION_ERROR';
          message = '请求参数验证失败';
        }
      } else {
        message = exceptionResponse as string;
        errorCode = this.getErrorCode(status);
      }
    } else if (exception instanceof Prisma.PrismaClientKnownRequestError) {
      // Prisma 已知错误特判：避免 raw error.message 泄露内部细节 + 转标准 HTTP 码。
      // 修 #463 元根因（meeting-attendance 模块用 @Res() 手动 catch + helper 兜底，
      // 不走本 filter；本分支覆盖其它所有走 NestJS 标准 throw 路径的模块）。
      if (exception.code === 'P2023') {
        // 字段类型不匹配（典型场景：uuid 列收到非法字符串）
        status = HttpStatus.BAD_REQUEST;
        errorCode = 'INVALID_ID_FORMAT';
        message = 'Invalid id format';
      } else if (exception.code === 'P2025') {
        // update / delete / findFirstOrThrow 找不到记录
        status = HttpStatus.NOT_FOUND;
        errorCode = 'NOT_FOUND';
        message = 'Record not found';
      } else {
        // 其它 Prisma 已知错误（P2002 唯一冲突、P2003 FK 失败等）：500 + 不暴露 raw
        status = HttpStatus.INTERNAL_SERVER_ERROR;
        errorCode = 'DATABASE_ERROR';
        message = '数据库操作失败';
        details =
          process.env.NODE_ENV === 'development'
            ? { prismaCode: exception.code, prismaMessage: exception.message }
            : undefined;
      }
    } else if (exception instanceof Error) {
      // 普通错误
      message = exception.message;
      details = process.env.NODE_ENV === 'development' ? exception.stack : undefined;
    }

    // 记录错误日志
    const logMessage = `${request.method} ${request.url} - ${status} - ${errorCode}`;
    if (status >= 500) {
      this.logger.error(
        logMessage,
        exception instanceof Error ? exception.stack : JSON.stringify(exception),
      );
    } else if (status >= 400) {
      this.logger.warn(logMessage);
    }

    const performanceOverride = this.getPerformanceErrorOverride(
      request,
      status,
      errorCode,
      errors,
    );
    if (performanceOverride) {
      errorCode = performanceOverride.code;
      message = performanceOverride.message;
    }

    // 构建错误响应
    const errorObject: any = {
      code: errorCode,
      message,
      stack:
        process.env.NODE_ENV === 'development' && exception instanceof Error
          ? exception.stack
          : undefined,
    };
    
    if (errors && errors.length > 0) {
      const formatted = this.formatValidationErrors(errors);
      if (details && typeof details === 'object') {
        errorObject.details = { ...details, errors: formatted };
      } else {
        errorObject.details = { errors: formatted };
      }
    } else if (details !== undefined) {
      errorObject.details = details;
    }
    
    const errorResponse: ApiErrorResponse = {
      success: false,
      error: errorObject,
      timestamp: new Date().toISOString(),
      path: request.url,
      method: request.method,
      statusCode: status,
    };

    // 如果还没有设置 X-Request-Id，生成一个
    if (!response.getHeader('X-Request-Id')) {
      const requestId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
      response.setHeader('X-Request-Id', requestId);
    }

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

  /**
   * 根据 HTTP 状态码获取默认错误代码
   */
  private getErrorCode(status: number): string {
    const errorCodes: Record<number, string> = {
      400: 'BAD_REQUEST',
      401: 'UNAUTHORIZED',
      403: 'FORBIDDEN',
      404: 'NOT_FOUND',
      409: 'CONFLICT',
      422: 'UNPROCESSABLE_ENTITY',
      429: 'TOO_MANY_REQUESTS',
      500: 'INTERNAL_SERVER_ERROR',
      502: 'BAD_GATEWAY',
      503: 'SERVICE_UNAVAILABLE',
      504: 'GATEWAY_TIMEOUT',
    };
    return errorCodes[status] || 'UNKNOWN_ERROR';
  }

  /**
   * 格式化验证错误
   */
  private formatValidationErrors(errors: any[]): FieldError[] {
    return errors.map((error) => {
      // 字符串错误
      if (typeof error === 'string') {
        return { field: '', message: error };
      }

      // class-validator 错误
      if (error.property && error.constraints) {
        const constraintKey = Object.keys(error.constraints)[0];
        return {
          field: error.property,
          message: error.constraints[constraintKey],
          value: error.value,
          constraint: constraintKey,
        };
      }

      // 已格式化的错误
      if (error.field && error.message) {
        return error;
      }

      // 其他格式
      return {
        field: error.field || '',
        message: error.message || String(error),
      };
    });
  }

  private getPerformanceErrorOverride(
    request: Request,
    status: number,
    errorCode: string,
    errors?: any[] | undefined,
  ): { code: string; message: string } | null {
    if (!request.url?.startsWith('/api/v1/performance')) {
      return null;
    }
    if (errorCode.startsWith('PERF_')) {
      return null;
    }

    if (status === HttpStatus.UNAUTHORIZED) {
      return { code: 'PERF_COMMON_001', message: '未认证或 Token 失效' };
    }
    if (status === HttpStatus.FORBIDDEN) {
      return { code: 'PERF_COMMON_002', message: '无权限访问资源' };
    }
    if (status === HttpStatus.BAD_REQUEST) {
      if (
        errors?.length ||
        ['VALIDATION_ERROR', 'BAD_REQUEST', 'Bad Request', 'INVALID_ID_FORMAT'].includes(errorCode)
      ) {
        return { code: 'PERF_COMMON_003', message: '参数校验失败' };
      }
    }
    if (status === HttpStatus.NOT_FOUND) {
      return { code: 'PERF_COMMON_004', message: '资源不存在' };
    }
    if (status >= HttpStatus.INTERNAL_SERVER_ERROR) {
      return { code: 'PERF_COMMON_005', message: '服务器内部错误' };
    }

    return null;
  }
}
