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);
  }
}

/**
 * ES 不可用且无降级路径（503）。
 * 仲裁依据：02-architecture-design.md §6.2
 */
export class EsUnavailableError extends ApplicationError {
  readonly type = "internal" as const;
  readonly statusCode = 503;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "MSG_ES_UNAVAILABLE", details);
  }
}

/**
 * Redis 不可用且无降级路径（503）。
 * 仲裁依据：02-architecture-design.md §6.2
 */
export class RedisUnavailableError extends ApplicationError {
  readonly type = "internal" as const;
  readonly statusCode = 503;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "MSG_REDIS_UNAVAILABLE", details);
  }
}

/**
 * Push Gateway 不可用（503）。
 * 仲裁依据：02-architecture-design.md §6.2 + coord M4（软失败，仅必要时抛出）
 */
export class PushGatewayUnavailableError extends ApplicationError {
  readonly type = "internal" as const;
  readonly statusCode = 503;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "MSG_PUSH_GATEWAY_UNAVAILABLE", details);
  }
}

/**
 * 通知模板不存在（404）。
 * 仲裁依据：02-architecture-design.md §6.2
 */
export class TemplateNotFoundError extends ApplicationError {
  readonly type = "not_found" as const;
  readonly statusCode = 404;
  constructor(templateCode: string) {
    super(
      `Notification template not found: ${templateCode}`,
      "MSG_TEMPLATE_NOT_FOUND",
      { templateCode },
    );
  }
}

/**
 * 模板渲染失败（变量缺失等，422）。
 * 仲裁依据：02-architecture-design.md §6.2
 */
export class TemplateRenderError extends ApplicationError {
  readonly type = "business" as const;
  readonly statusCode = 422;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "MSG_TEMPLATE_RENDER_ERROR", details);
  }
}

/**
 * 通知频率超限（429）。
 * 仲裁依据：02-architecture-design.md §6.2（NotificationPreference.frequency_limit 预留）
 */
export class RateLimitExceededError extends ApplicationError {
  readonly type = "business" as const;
  readonly statusCode = 429;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "MSG_RATE_LIMIT_EXCEEDED", details);
  }
}
