/**
 * In-memory scoped list event emitter (D-04, D-18).
 *
 * Module-level singleton — one EventEmitter shared across all route handlers
 * in this Node.js process. Per-list channels keyed as `list:${listId}` ensure
 * events for one list cannot be received by subscribers of another list.
 *
 * Fan-out mechanism justification (D-18): In-memory EventEmitter, not Redis.
 * The API runs as a single Node process (no replicas), so Redis pub/sub adds
 * a network hop and operational overhead for zero benefit. The abstraction
 * boundary (callers never touch the EventEmitter directly) makes a future
 * Redis swap mechanical inside this module.
 *
 * Exports: publishListEvent, subscribeListEvents, ListEvent
 * Source: RESEARCH.md Finding 1 verbatim pattern.
 */

import { EventEmitter } from 'node:events';

// Module-level singleton — one emitter shared across all route handlers
// in this Node.js process.
const emitter = new EventEmitter();
emitter.setMaxListeners(200); // 100 members × 2 devices, generous headroom (T-04-04)

/**
 * Event type union for list change notifications.
 * All events carry the originating listId and an opaque payload.
 */
export type ListEvent = {
  type: 'item:added' | 'item:updated' | 'item:deleted' | 'list:updated' | 'list:deleted';
  listId: number;
  payload: unknown;
};

/**
 * Broadcast an event to all SSE subscribers watching this list.
 * Channel is keyed by listId — events for list A never reach subscribers of list B.
 */
export function publishListEvent(listId: number, event: ListEvent): void {
  emitter.emit(`list:${listId}`, event);
}

/**
 * Subscribe to events for a specific list.
 * Returns an unsubscribe function; call it to stop delivery to this handler.
 */
export function subscribeListEvents(
  listId: number,
  handler: (event: ListEvent) => void,
): () => void {
  const channel = `list:${listId}`;
  emitter.on(channel, handler);
  return () => emitter.off(channel, handler);
}
