/**
 * relay-web local error taxonomy. Typed, explicit errors (coding-style.md "Error Handling")
 * so callers never swallow failures or render partial objects.
 */

/** Base class for every relay-web boundary error. */
export class RelayWebError extends Error {
  constructor(message: string) {
    super(message)
    this.name = 'RelayWebError'
  }
}

/** Thrown by readConfig when the origin is not a valid tenant subdomain (fail-fast, T1). */
export class ConfigError extends RelayWebError {
  constructor(message: string) {
    super(message)
    this.name = 'ConfigError'
  }
}

/** Discriminated kinds for control-plane API failures (T2). */
export type ApiErrorKind =
  | 'unauthenticated' // 401 — session missing/expired; surface re-login
  | 'forbidden' // 403 — INV1/INV6 upstream denial (foreign host_id etc.)
  | 'http' // other non-2xx
  | 'parse' // response failed Zod validation (never return a torn object)
  | 'network' // fetch itself rejected

/** Control-plane HTTP client error. `kind` drives the UI response (re-login, error banner, …). */
export class ApiError extends RelayWebError {
  readonly kind: ApiErrorKind
  readonly status: number | null

  constructor(kind: ApiErrorKind, message: string, status: number | null = null) {
    super(message)
    this.name = 'ApiError'
    this.kind = kind
    this.status = status
  }
}
