/**
 * Structural surface @shade/files needs from a Shade instance.
 *
 * Defining this locally — instead of `import type { Shade } from '@shade/sdk'`
 * — breaks the @shade/sdk ↔ @shade/files dependency cycle. Without this
 * break, a consumer that installs @shade/sdk from a registry ends up with
 * two distinct `Shade` classes in `node_modules` (one from
 * `@shade/sdk/node_modules/@shade/files/.../Shade`, one from
 * `@shade/sdk/Shade`). TypeScript treats them as nominally different types,
 * raising `this is not assignable to Shade` from inside SDK methods that
 * pass `this` into `createFilesNamespace`.
 *
 * The Shade class structurally implements every member listed below, so
 * `createFilesNamespace(this)` from the SDK side compiles regardless of
 * how many copies of @shade/sdk a consumer's package manager installs.
 *
 * Member signatures match Shade's exactly so this is a structural
 * subtype, not a parallel API.
 */
import type { ShadeEnvelope } from '@shade/core';
import type {
  IncomingTransfer,
  TransferHandle,
  TransferOptions,
} from '@shade/transfer';
import type { ObservabilityHook } from '@shade/observability';

export interface ShadeBridge {
  /** Address that names this Shade instance to peers. */
  readonly myAddress: string;

  /** Encrypt + send `plaintext` to `peer`; returns the wire envelope. */
  send(peer: string, plaintext: string): Promise<ShadeEnvelope>;

  /**
   * Decrypt an inbound envelope from `peer` and return the plaintext.
   * Used by the request-response RPC route on the server side.
   */
  receive(peer: string, envelope: ShadeEnvelope): Promise<string>;

  /**
   * Subscribe to incoming ratchet plaintext. Returns an unsubscribe.
   * Handlers may be sync or async; async handlers are awaited in
   * registration order.
   */
  onMessage(
    handler: (from: string, plaintext: string) => void | Promise<void>,
  ): () => void;

  /**
   * Upload bytes via the SDK's transfer engine. Required when the bridge
   * is used with `streams` content I/O (read/write > 256 KiB).
   */
  upload(opts: TransferOptions): Promise<TransferHandle>;

  /** Subscribe to incoming transfers initiated by a peer. */
  onIncomingTransfer(
    handler: (incoming: IncomingTransfer) => void | Promise<void>,
  ): Promise<() => void>;

  /** Fingerprint accessor for the trust-gate hooks. */
  getFingerprintFor(peer: string): Promise<string>;

  /**
   * Optional inheritable observability bus. Files inherits the bus when
   * the SDK passes one in via the namespace; otherwise files runs without
   * observability hooks.
   */
  getObservability?(): ObservabilityHook | undefined;

  /** Optional control-envelope passthrough used by the WebRTC bridge. */
  deliverControlEnvelope?(peer: string, envelope: ShadeEnvelope): Promise<void>;

  /**
   * Hand a freshly-decoded wire envelope (control or chunk) to the
   * transfer engine. Required by the pull-mode HTTP client when it
   * drains queued events from the server: each polled chunk / control
   * envelope is dispatched here so the engine sees it just as if it
   * had arrived via an HTTP POST on `/v1/transfer/...`.
   */
  acceptTransferEnvelope?(from: string, env: ShadeEnvelope | Uint8Array): Promise<void>;

  /**
   * Configure the transfer stack. Called by the pull-mode HTTP client
   * to point the browser's outgoing chunks + control envelopes at the
   * server's transferQueueRoute mount. Optional because the
   * server-to-server path uses a separate, app-driven configuration.
   */
  configureTransfers?(opts: {
    resolveBaseUrl?: (peerAddress: string) => Promise<string>;
    transport?: unknown;
    envelopeTransport?: unknown;
  }): void;
}
