/**
 * listEmitter — scoped fan-out correctness tests (D-04).
 *
 * These are pure-unit tests — no DB or HTTP server needed.
 * Tests 1-4 cover publishListEvent / subscribeListEvents behavior.
 *
 * Critical: Test 2 is the D-04 negative assertion — an event published
 * for list 2 MUST NOT reach a handler subscribed only to list 1.
 *
 * Run: pnpm --filter @familysync/api exec vitest run tests/lib/listEmitter.test.ts
 */

import { describe, it, expect, vi } from 'vitest';
import {
  publishListEvent,
  subscribeListEvents,
  type ListEvent,
} from '../../src/lib/listEmitter.js';

describe('listEmitter — scoped fan-out correctness (D-04)', () => {
  const makeEvent = (listId: number): ListEvent => ({
    type: 'item:added',
    listId,
    payload: { id: 1, text: 'milk', checked: false },
  });

  it('publishListEvent delivers to a subscriber of the matching listId (Test 1)', () => {
    const received: ListEvent[] = [];
    const unsub = subscribeListEvents(1, (ev) => received.push(ev));

    const ev = makeEvent(1);
    publishListEvent(1, ev);

    unsub();
    expect(received).toHaveLength(1);
    expect(received[0]).toBe(ev);
  });

  it('publishListEvent does NOT deliver to a subscriber of a different listId (Test 2 — D-04 negative)', () => {
    const received: ListEvent[] = [];
    const unsub = subscribeListEvents(1, (ev) => received.push(ev));

    publishListEvent(2, makeEvent(2));

    unsub();
    expect(received).toHaveLength(0);
  });

  it('the unsubscribe closure stops future delivery (Test 3)', () => {
    const received: ListEvent[] = [];
    const unsub = subscribeListEvents(3, (ev) => received.push(ev));

    publishListEvent(3, makeEvent(3));
    unsub();
    publishListEvent(3, makeEvent(3));

    expect(received).toHaveLength(1);
  });

  it('multiple handlers on the same list channel all receive the event (Test 4)', () => {
    const calls: number[] = [];
    const unsub1 = subscribeListEvents(4, () => calls.push(1));
    const unsub2 = subscribeListEvents(4, () => calls.push(2));
    const unsub3 = subscribeListEvents(4, () => calls.push(3));

    publishListEvent(4, makeEvent(4));

    unsub1();
    unsub2();
    unsub3();

    expect(calls).toHaveLength(3);
    expect(calls).toContain(1);
    expect(calls).toContain(2);
    expect(calls).toContain(3);
  });

  it('emitter handles 100+ concurrent subscribers without MaxListeners error (D-18 scale check)', () => {
    const N = 120;
    const unsubs: Array<() => void> = [];
    const handler = vi.fn();

    for (let i = 0; i < N; i++) {
      unsubs.push(subscribeListEvents(5, handler));
    }

    publishListEvent(5, makeEvent(5));

    unsubs.forEach((u) => u());

    expect(handler).toHaveBeenCalledTimes(N);
  });
});
