import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
import { createInteractionContext } from './interaction-context';
const suite = createLogicSuite('interaction-context factory');
suite('once runs the factory a single time and memoises the result', () => {
    const { context } = createInteractionContext('id-1');
    let calls = 0;
    const first = context.once('ws', () => {
        calls += 1;
        return { socket: true };
    });
    const second = context.once('ws', () => {
        calls += 1;
        return { socket: false };
    });
    assert.is(calls, 1, 'factory ran once');
    assert.is(second, first, 'the memoised value is returned on the second call');
});
suite('subscribe/notify fans out to listeners; unsubscribe stops them', () => {
    const { context } = createInteractionContext('id-2');
    let a = 0;
    let b = 0;
    const unsubA = context.subscribe(() => (a += 1));
    context.subscribe(() => (b += 1));
    context.notify();
    assert.is(a, 1);
    assert.is(b, 1);
    unsubA();
    context.notify();
    assert.is(a, 1, 'unsubscribed listener no longer fires');
    assert.is(b, 2, 'remaining listener still fires');
});
suite('a throwing subscriber does not stop the others', () => {
    const { context } = createInteractionContext('id-3');
    let reached = false;
    context.subscribe(() => {
        throw new Error('boom');
    });
    context.subscribe(() => (reached = true));
    context.notify();
    assert.ok(reached, 'later subscriber still ran after an earlier one threw');
});
suite('dispose runs every onDispose callback once, then is idempotent', () => {
    const { context, dispose } = createInteractionContext('id-4');
    let count = 0;
    context.onDispose(() => (count += 1));
    context.onDispose(() => (count += 1));
    dispose();
    assert.is(count, 2, 'both disposers ran');
    dispose();
    assert.is(count, 2, 'a second dispose is a no-op');
});
suite('onDispose registered after dispose runs immediately', () => {
    const { context, dispose } = createInteractionContext('id-5');
    dispose();
    let ran = false;
    context.onDispose(() => (ran = true));
    assert.ok(ran, 'late onDispose runs immediately so no resource leaks');
});
suite('notify after dispose is a no-op (listeners cleared)', () => {
    const { context, dispose } = createInteractionContext('id-6');
    let fired = 0;
    context.subscribe(() => (fired += 1));
    dispose();
    context.notify();
    assert.is(fired, 0, 'no listeners fire after dispose');
});
suite('once after dispose returns null without running the factory', () => {
    const { context, dispose } = createInteractionContext('id-7');
    dispose();
    let calls = 0;
    const result = context.once('late', () => {
        calls += 1;
        return { socket: true };
    });
    assert.is(calls, 0, 'the factory never ran on an ended interaction (no leaked resource)');
    assert.is(result, null, 'once returns null after dispose');
});
suite.run();
