/**
 * parent-bff 统一错误体系（对齐 02-architecture-design.md §6.2）。
 *
 * 错误码前缀统一 BFF_PARENT_*（C1 仲裁：BFF 在前，不是 PARENT_BFF_）。
 *
 * 错误码清单：
 * - BFF_PARENT_VALIDATION_ERROR (400)
 * - BFF_PARENT_UNAUTHORIZED (401)
 * - BFF_PARENT_CHILD_NOT_BOUND (403) — ChildGuard 拦截
 * - BFF_PARENT_NOT_FOUND (404)
 * - BFF_PARENT_CONFLICT (409)
 * - BFF_PARENT_BUSINESS_ERROR (422)
 * - BFF_PARENT_BAD_GATEWAY (502)
 * - BFF_PARENT_GATEWAY_TIMEOUT (504)
 * - BFF_PARENT_SERVICE_UNAVAILABLE (503) — 熔断器开启（P6）
 * - BFF_PARENT_INTERNAL_ERROR (500)
 */
export type ErrorType =
  | "validation"
  | "unauthorized"
  | "child_not_bound"
  | "not_found"
  | "conflict"
  | "business"
  | "bad_gateway"
  | "gateway_timeout"
  | "service_unavailable"
  | "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;
  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, "BFF_PARENT_VALIDATION_ERROR", details);
  }
}

export class UnauthorizedError extends ApplicationError {
  readonly type = "unauthorized" as const;
  readonly statusCode = 401;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "BFF_PARENT_UNAUTHORIZED", details);
  }
}

/**
 * ChildGuard 越权拦截：childId 不在家长绑定列表。
 *
 * 对齐 02 §2.3：DataScope=CHILDREN 防御，BFF 层先拦截减少无效下游调用。
 */
export class ChildNotBoundError extends ApplicationError {
  readonly type = "child_not_bound" as const;
  readonly statusCode = 403;
  constructor(
    parentId: string,
    requestedChildId: string,
    boundChildren: string[],
  ) {
    super(
      `Child ${requestedChildId} not bound to parent ${parentId}`,
      "BFF_PARENT_CHILD_NOT_BOUND",
      {
        parentId,
        requestedChildId,
        boundChildren,
      },
    );
  }
}

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

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

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

/**
 * 下游服务返回非 ok 或 gRPC rejected。
 */
export class BadGatewayError extends ApplicationError {
  readonly type = "bad_gateway" as const;
  readonly statusCode = 502;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "BFF_PARENT_BAD_GATEWAY", details);
  }
}

/**
 * 下游调用超时。
 */
export class GatewayTimeoutError extends ApplicationError {
  readonly type = "gateway_timeout" as const;
  readonly statusCode = 504;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "BFF_PARENT_GATEWAY_TIMEOUT", details);
  }
}

/**
 * 熔断器开启（P6 opossum 熔断器触发）。
 */
export class ServiceUnavailableError extends ApplicationError {
  readonly type = "service_unavailable" as const;
  readonly statusCode = 503;
  constructor(message: string, details?: ErrorDetails) {
    super(message, "BFF_PARENT_SERVICE_UNAVAILABLE", details);
  }
}

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