// Shared types for @picloud/client.

/** Returns the current bearer token (or null) before each HTTP request. */
export type AuthTokenProvider = () => string | null | undefined | Promise<string | null | undefined>;

export interface PicloudClientOptions {
  /** Base URL of the PiCloud deployment, e.g. `https://api.example.com`. */
  baseURL: string;
  /**
   * Optional: returns the current bearer token, called before each
   * request. The client doesn't manage tokens — it just sends them.
   */
  getAuthToken?: AuthTokenProvider;
  /**
   * Optional fetch implementation (defaults to the global `fetch`).
   * Injected mainly for tests / non-browser runtimes.
   */
  fetch?: typeof fetch;
}

/** A realtime event as delivered over SSE. */
export interface RealtimeEvent<T = unknown> {
  topic: string;
  message: T;
  published_at: string;
}

/**
 * Minimal validator shape for the optional runtime-validation adapter.
 * A Zod schema satisfies this directly (`schema.parse`); for Valibot,
 * wrap it: `{ parse: (i) => v.parse(schema, i) }`. No hard dep on either.
 */
export interface Validator<T> {
  parse: (input: unknown) => T;
}

/** Thrown when an endpoint call returns a non-2xx status. */
export class PicloudHttpError extends Error {
  readonly status: number;
  readonly body: unknown;
  constructor(status: number, message: string, body: unknown) {
    super(message);
    this.name = 'PicloudHttpError';
    this.status = status;
    this.body = body;
  }
}

export interface SubscribeOptions<T = unknown> {
  /**
   * Subscriber token for `auth_mode = 'token'` topics. Obtained from one
   * of your app's script endpoints (which calls
   * `pubsub::subscriber_token`). Sent as `?token=` (EventSource-parity).
   */
  token?: string;
  /**
   * Called when a (re)connect is rejected with 401 — typically an
   * expired token. Return a fresh token to retry immediately, or
   * null/undefined to stop and surface the error.
   */
  onTokenExpired?: () => string | null | undefined | Promise<string | null | undefined>;
  /** Called on a terminal error (after retries are exhausted or aborted). */
  onError?: (err: unknown) => void;
  /** Optional runtime validation of each event's `message`. */
  validate?: Validator<T>;
  /** Max reconnect backoff in ms (default 30_000). */
  maxBackoffMs?: number;
  /** Base reconnect backoff in ms (default 1_000). */
  baseBackoffMs?: number;
}

/** Cancels a realtime subscription. */
export type Unsubscribe = () => void;
