import { ReactNode } from 'react';
import { ServerFrame } from '@platform-modules/realtime';

/**
 * `@platform-modules/realtime-react` — headless client adapter for the `@platform-modules/realtime` wire contract.
 *
 * Depends only on the isomorphic frame types from `@platform-modules/realtime` (type-only) plus a
 * `react` peer. Deliberately small: each hook owns ONE WebSocket to one URL and surfaces
 * its status. Sharing a connection across a subtree, multiplexing rooms over one socket,
 * and reconnect/backoff policy are the HOST's concern (to reconnect, re-key the hook by
 * changing `url`) — see the realtime module spec. Adapters stay headless: hook +
 * render-prop, the host owns all markup.
 */
/** Lifecycle of a channel's socket. `closed` is terminal — re-key (`url`) to reconnect. */
type ConnectionStatus = 'idle' | 'connecting' | 'open' | 'closed';
interface UseChannelOptions<F extends ServerFrame> {
    /** Invoked for every parsed frame. Stored in a ref — changing its identity does NOT reconnect. */
    onFrame?: (frame: F) => void;
    /** Invoked on every status transition. Ref-stable like `onFrame`. */
    onStatus?: (status: ConnectionStatus) => void;
    /** WebSocket subprotocol(s), forwarded verbatim to the constructor. */
    protocols?: string | string[];
}
/**
 * Subscribe to a realtime channel: open ONE WebSocket to `url`, parse {@link ServerFrame}s,
 * and surface connection status + the last frame. Pass `url = null` to stay idle (e.g.
 * before authentication). Closes the socket (code 1000) on unmount or when `url`/`protocols`
 * change; StrictMode-safe via a per-effect disposal guard.
 */
declare function useChannel<F extends ServerFrame = ServerFrame>(url: string | null, options?: UseChannelOptions<F>): Channel<F>;
interface UsePresenceOptions<F extends ServerFrame> {
    /** Frame `type` that carries a presence roster. Default `'presence'`. */
    presenceType?: string;
    /** Extract the online-id list from a presence frame. Default reads a string[] `online` field. */
    select?: (frame: F) => readonly string[];
    /** WebSocket subprotocol(s), forwarded to the underlying channel. */
    protocols?: string | string[];
}
interface Presence {
    /** Ids reported online by the most recent presence frame (empty until one arrives). */
    online: readonly string[];
    /** Underlying channel status. */
    status: ConnectionStatus;
}
/**
 * Derive an online roster from presence frames on a channel, built on {@link useChannel}.
 * Presence is a single-source convention, so the frame `type` and the roster
 * extractor are configurable rather than hard-coded. The roster resets when `url` changes
 * (a new channel starts empty).
 */
declare function usePresence<F extends ServerFrame = ServerFrame>(url: string | null, options?: UsePresenceOptions<F>): Presence;
interface ChannelProps<F extends ServerFrame> extends UseChannelOptions<F> {
    /** Channel URL, or `null` to stay idle. */
    url: string | null;
    /** Headless render-prop: receives channel state, returns host markup. The host owns all DOM. */
    render: (channel: Channel<F>) => ReactNode;
}
interface Channel<F extends ServerFrame> {
    /** Current connection state. */
    status: ConnectionStatus;
    /** Last parsed frame, or `null` before the first valid message. */
    lastFrame: F | null;
    /** Send to the server. Returns `false` (no-op) unless the socket is OPEN. */
    send: (data: string | ArrayBufferLike | ArrayBufferView | Blob) => boolean;
}
/**
 * Headless render-prop wrapper over {@link useChannel} for hosts that prefer a component
 * to a hook. Renders nothing of its own — the host owns every element via `render`.
 */
declare function Channel<F extends ServerFrame = ServerFrame>({ url, render, ...options }: ChannelProps<F>): ReactNode;

export { Channel, type ChannelProps, type ConnectionStatus, type Presence, type UseChannelOptions, type UsePresenceOptions, useChannel, usePresence };
