/**
 * notif-bus — tiny per-tab pub/sub for routing WebSocket frames to React subscribers.
 *
 * Singleton module: one Map per browser tab. WebSocket messages are dispatched
 * to all `on(channel, fn)` subscribers for that channel.
 *
 * @wave 7 — client hook + bell wire-up
 */

import { captureCaught } from '@/lib/observability';

type Handler = (env: unknown) => void;

const subs = new Map<string, Set<Handler>>();

/**
 * Subscribe to a channel. Returns an unsubscribe function.
 * Idempotent — adding the same fn twice has no effect.
 */
export function on(channel: string, fn: Handler): () => void {
  let set = subs.get(channel);
  if (!set) {
    set = new Set();
    subs.set(channel, set);
  }
  set.add(fn);
  return () => {
    set!.delete(fn);
    if (set!.size === 0) subs.delete(channel);
  };
}

/**
 * Emit an event to all subscribers of a channel.
 * Swallows individual handler errors to avoid one bad subscriber killing others.
 */
export function emit(channel: string, env: unknown): void {
  subs.get(channel)?.forEach((h) => {
    try {
      h(env);
    } catch (err) {
      captureCaught(err, {
        scope: 'lib.notif-bus.emit.handler',
        severity: 'warning',
      });
    }
  });
}

/**
 * Returns the list of currently subscribed channels.
 * Used by the WS open handler to (re-)subscribe after reconnect.
 */
export function channels(): string[] {
  return [...subs.keys()];
}
