// Global connectivity signal. `online` is false while the app is actively failing to
// reach the gateway — a unary call retrying after a transport/rate-limit failure, or the live
// stream dropped. The transport and the live-stream owner report transitions; the UI reads
// `connection.online` to show the "Connecting…" indicator and to softly disable proactive
// actions. In mock mode nothing ever reports trouble, so it simply stays online.
//
// Recovery is guaranteed by a reachability watcher: while offline it periodically fires a
// registered probe (a lightweight read) until one succeeds, so the indicator clears even when no
// other traffic is in flight.

import { backoffMs } from './retry';

let online = $state(true);
let watchTimer: ReturnType<typeof setTimeout> | null = null;
let probe: (() => Promise<void>) | null = null;

export const connection = {
  /** online is true when the app believes it can reach the gateway. */
  get online(): boolean {
    return online;
  },
};

/** registerProbe installs the reachability probe the watcher fires while offline. The transport
 *  wires a cheap authenticated read; it should reject when there is no session. */
export function registerProbe(fn: () => Promise<void>): void {
  probe = fn;
}

/** reportOnline marks the gateway reachable and stops the watcher. */
export function reportOnline(): void {
  online = true;
  if (watchTimer) {
    clearTimeout(watchTimer);
    watchTimer = null;
  }
}

/** reportOffline marks the gateway unreachable and starts the reachability watcher (once). */
export function reportOffline(): void {
  online = false;
  if (!watchTimer && probe) scheduleProbe(1);
}

/** resetConnection restores the online state and stops the watcher (e.g. on logout). */
export function resetConnection(): void {
  reportOnline();
}

function scheduleProbe(attempt: number): void {
  watchTimer = setTimeout(
    () => {
      watchTimer = null;
      if (online || !probe) return;
      probe().then(reportOnline, () => scheduleProbe(Math.min(attempt + 1, 6)));
    },
    backoffMs(attempt),
  );
}
