export type ErrorType =
  | 'validation'
  | 'not_found'
  | 'permission_denied'
  | 'conflict'
  | 'business'
  | 'database'
  | 'internal';

export interface ErrorDetails {
  [key: string]: unknown;
}

export abstract class ApplicationError extends Error {
  abstract readonly type: ErrorType;
  abstract readonly statusCode: number;
  readonly code: string;
  readonly details?: ErrorDetails;
  // FIX #1: traceId 改为可写，以便 GlobalErrorFilter 注入请求级 traceId
  traceId?: string;

  constructor(message: string, code: string, details?: ErrorDetails) {
    super(message);
    this.name = this.constructor.name;
    this.code = code;
    this.details = details;
  }

  toJSON(): Record<string, unknown> {
    return {
      success: false,
      error: {
        code: this.code,
        message: this.message,
        details: this.details,
        traceId: this.traceId,
      },
    };
  }
}

export class ValidationError extends ApplicationError {
  readonly type = 'validation' as const;
  readonly statusCode = 400;
  constructor(message: string, details?: ErrorDetails) {
    super(message, 'MSG_VALIDATION_ERROR', details);
  }
}

export class NotFoundError extends ApplicationError {
  readonly type = 'not_found' as const;
  readonly statusCode = 404;
  constructor(resource: string, id: string) {
    super(`${resource} not found: ${id}`, 'MSG_NOT_FOUND', { resource, id });
  }
}

export class PermissionDeniedError extends ApplicationError {
  readonly type = 'permission_denied' as const;
  readonly statusCode = 403;
  constructor(permission: string) {
    super(`Permission denied: ${permission}`, 'MSG_PERMISSION_DENIED', { permission });
  }
}

export class ConflictError extends ApplicationError {
  readonly type = 'conflict' as const;
  readonly statusCode = 409;
  constructor(message: string, details?: ErrorDetails) {
    super(message, 'MSG_CONFLICT', details);
  }
}

export class BusinessError extends ApplicationError {
  readonly type = 'business' as const;
  readonly statusCode = 422;
  constructor(message: string, details?: ErrorDetails) {
    super(message, 'MSG_BUSINESS_ERROR', details);
  }
}

export class DatabaseError extends ApplicationError {
  readonly type = 'database' as const;
  readonly statusCode = 500;
  constructor(message: string, details?: ErrorDetails) {
    super(message, 'MSG_DATABASE_ERROR', details);
  }
}

export class InternalError extends ApplicationError {
  readonly type = 'internal' as const;
  readonly statusCode = 500;
  constructor(message: string, details?: ErrorDetails) {
    super(message, 'MSG_INTERNAL_ERROR', details);
  }
}
