/**
 * Coordinator bridge for the section runtime engine adapter (M7 —
 * Variant C, layered).
 *
 * Unlike the DOM / framework-error bridges (which translate
 * **outputs** into I/O), the coordinator bridge is an **input source**:
 * it listens to a `ToolkitCoordinator` and feeds the resulting events
 * into the core via the `dispatchCoreInput` callback supplied by the
 * adapter.
 *
 * Responsibilities:
 *   1. **Framework-error subscription.** When the coordinator reports
 *      a framework error through its bus, dispatch a
 *      `{ kind: "framework-error" }` core input. Listener isolation
 *      matches `FrameworkErrorBus`: a throwing bridge handler is
 *      caught and `console.warn`-logged so the original fan-out is
 *      not interrupted.
 *
 *   2. **Section-controller resolution.** When the host calls
 *      `resolveSectionController({ ... })`, the bridge invokes
 *      `coordinator.getOrCreateSectionController({ ... })` and, on
 *      successful resolution, dispatches
 *      `{ kind: "section-controller-resolved" }` to the core. Init
 *      tokens guard against late resolutions overwriting a more
 *      recent cohort (mirrors `SectionRuntimeEngine.initialize`'s
 *      `activeInitToken` pattern).
 *
 *   3. **Disposal.** On `dispose()`, the bridge unsubscribes from the
 *      framework-error bus and (if the engine owns the section
 *      controller for the cohort) calls
 *      `coordinator.disposeSectionController({ ... })`. It does
 *      **not** dispose the coordinator itself — the coordinator's
 *      lifetime is owned by the toolkit CE / host, not by the engine.
 *
 * Disposal is idempotent: calling `dispose()` twice is a no-op.
 *
 * The bridge **must not** import `svelte`.
 */
export function createCoordinatorBridge(options) {
    const { coordinator, dispatchCoreInput } = options;
    let activeInitToken = 0;
    let activeCohort = null;
    let unsubscribeController = null;
    let disposed = false;
    const unsubscribeFrameworkErrors = coordinator.subscribeFrameworkErrors((model) => {
        try {
            dispatchCoreInput({ kind: "framework-error", error: model });
        }
        catch (error) {
            console.warn("[CoordinatorBridge] framework-error dispatch failed:", error);
        }
    });
    function detachControllerSubscription() {
        if (!unsubscribeController)
            return;
        try {
            unsubscribeController();
        }
        catch (error) {
            console.warn("[CoordinatorBridge] controller unsubscribe failed:", error);
        }
        unsubscribeController = null;
    }
    async function resolveSectionController(args) {
        if (disposed)
            return;
        activeInitToken += 1;
        const token = activeInitToken;
        activeCohort = args.cohort;
        const controller = await coordinator.getOrCreateSectionController({
            sectionId: args.cohort.sectionId,
            attemptId: args.cohort.attemptId || undefined,
            input: {
                section: args.section,
                sectionId: args.cohort.sectionId,
                assessmentId: args.assessmentId,
                view: args.view,
            },
            updateExisting: true,
            createDefaultController: args.createDefaultController,
        });
        // Drop late resolutions — a cohort change or dispose may have
        // rolled the token forward while we awaited the coordinator.
        if (token !== activeInitToken || disposed)
            return;
        detachControllerSubscription();
        args.onControllerResolved?.(controller);
        const getCompositionModel = controller.getCompositionModel;
        args.onCompositionChanged?.(getCompositionModel?.());
        if (typeof controller.subscribe === "function") {
            unsubscribeController = controller.subscribe((_event) => {
                if (token !== activeInitToken || disposed)
                    return;
                args.onCompositionChanged?.(getCompositionModel?.());
            });
        }
        dispatchCoreInput({ kind: "section-controller-resolved" });
    }
    async function dispose() {
        if (disposed)
            return;
        disposed = true;
        activeInitToken += 1;
        detachControllerSubscription();
        try {
            unsubscribeFrameworkErrors();
        }
        catch (error) {
            console.warn("[CoordinatorBridge] framework-error unsubscribe failed:", error);
        }
        const cohort = activeCohort;
        activeCohort = null;
        if (cohort) {
            try {
                await coordinator.disposeSectionController({
                    sectionId: cohort.sectionId,
                    attemptId: cohort.attemptId || undefined,
                });
            }
            catch (error) {
                console.warn("[CoordinatorBridge] section-controller dispose failed:", error);
            }
        }
    }
    return { resolveSectionController, dispose };
}
//# sourceMappingURL=coordinator-bridge.js.map