import { __awaiter } from "tslib";
import { assert, createComponentSuite } from '@genesislcap/foundation-testing';
import { DOM } from '@genesislcap/web-core';
import { AiChatInteractionWrapper } from './chat-interaction-wrapper';
// Hold a reference so the custom-element registration isn't tree-shaken.
AiChatInteractionWrapper;
/**
 * Minimal stand-in for a real interaction widget. The wrapper instantiates the
 * element named by `componentName` and assigns `interactionId`/`interaction` onto
 * it (GENC-1390); the tests read `interaction` back to verify which interaction the
 * rendered widget belongs to and its pending/resolved state.
 */
const FAKE_WIDGET = 'test-interaction-widget';
if (!customElements.get(FAKE_WIDGET)) {
    customElements.define(FAKE_WIDGET, class extends HTMLElement {
    });
}
/**
 * Renders a first interaction into a freshly-mounted wrapper.
 *
 * `componentName` is assigned last on purpose. The suite hands us an
 * already-connected element, so the only render trigger left is
 * `componentNameChanged`; setting it last means that render sees `data` and
 * `interactionId` already in place — reproducing production, where the initial
 * widget renders in `connectedCallback` with every bound property present. This
 * keeps the *first* render correct on both the patched and unpatched code so
 * that the id-change rebind is the only behaviour each test isolates.
 */
function renderFirstInteraction(element) {
    return __awaiter(this, void 0, void 0, function* () {
        yield DOM.nextUpdate();
        element.data = { label: 'interaction-a' };
        element.interactionId = 'id-a';
        element.componentName = FAKE_WIDGET;
        yield DOM.nextUpdate();
    });
}
const Suite = createComponentSuite('AiChatInteractionWrapper', 'ai-chat-interaction-wrapper');
/**
 * Regression for the cog-menu toggle misalignment: FAST's `repeat` reconciles
 * the message list by array index (it has no key function), so toggling "Tool
 * calls"/"Thinking" re-filters the visible messages and rebinds an existing
 * row's wrapper to a *different* interaction. When both interactions use the
 * same component, `componentNameChanged` doesn't fire — so the wrapper must
 * re-render on `interactionId` change, or the previous interaction's widget
 * stays mounted under the new message.
 */
Suite('re-renders the hosted widget when interactionId changes with the same componentName', (_a) => __awaiter(void 0, [_a], void 0, function* ({ element }) {
    var _b, _c;
    yield renderFirstInteraction(element);
    const firstWidget = element.container.firstElementChild;
    assert.ok(firstWidget, 'a widget is rendered for the first interaction');
    assert.equal((_b = firstWidget.interaction) === null || _b === void 0 ? void 0 : _b.data, { label: 'interaction-a' });
    // Rebind the reused wrapper to a different interaction that happens to use
    // the same component — `data` then `interactionId`, mirroring the template's
    // property-binding order. `componentName` is unchanged, so the only thing
    // that can drive a re-render is the interactionId hook.
    element.data = { label: 'interaction-b' };
    element.interactionId = 'id-b';
    yield DOM.nextUpdate();
    const secondWidget = element.container.firstElementChild;
    assert.is.not(secondWidget, firstWidget, 'the stale widget is replaced, not left mounted');
    assert.equal((_c = secondWidget.interaction) === null || _c === void 0 ? void 0 : _c.data, { label: 'interaction-b' }, 'the rendered widget reflects the new interaction, not the stale one');
}));
/**
 * Resolving an interaction in place (the user answers it) must forward the
 * result without tearing down and rebuilding the widget — only a genuine change
 * of interaction identity should rebuild.
 */
Suite('forwards resolved in place without rebuilding the widget', (_a) => __awaiter(void 0, [_a], void 0, function* ({ element }) {
    var _b, _c, _d;
    yield renderFirstInteraction(element);
    const widget = element.container.firstElementChild;
    assert.is((_b = widget.interaction) === null || _b === void 0 ? void 0 : _b.status, 'pending', 'the widget starts pending');
    element.resolved = { status: 'approved' };
    yield DOM.nextUpdate();
    assert.is(element.container.firstElementChild, widget, 'resolving in place must not rebuild the widget');
    assert.is((_c = widget.interaction) === null || _c === void 0 ? void 0 : _c.status, 'resolved', 'the widget transitions to resolved in place');
    assert.equal(((_d = widget.interaction) === null || _d === void 0 ? void 0 : _d.status) === 'resolved' ? widget.interaction.result : undefined, { status: 'approved' }, 'the resolved result is forwarded to the widget');
}));
/**
 * When no live `InteractionContext` exists for the interaction — it has resolved and the driver
 * dropped it (the `resolved` binding can lag a render behind during a layout rebuild), or the widget
 * is rendered outside the normal host flow (as here: no host on the root) — the wrapper must hand the
 * widget an INERT context whose `once` refuses, never a live throwaway. A live throwaway re-ran the
 * widget's open-once side effect on the remount following a resolve, re-opening a just-closed side
 * panel and looping the layout rebuild (GENC-1390).
 */
Suite('falls back to an inert context (once refuses) when there is no live context', (_a) => __awaiter(void 0, [_a], void 0, function* ({ element }) {
    var _b, _c;
    yield renderFirstInteraction(element);
    const widget = element.container.firstElementChild;
    assert.is((_b = widget.interaction) === null || _b === void 0 ? void 0 : _b.status, 'pending', 'the widget is pending');
    const ctx = ((_c = widget.interaction) === null || _c === void 0 ? void 0 : _c.status) === 'pending' ? widget.interaction.interactionContext : undefined;
    assert.ok(ctx, 'a context is still provided so the widget does not crash on a missing one');
    let ran = 0;
    const result = ctx.once('open-review-panel', () => {
        ran += 1;
        return 'opened';
    });
    assert.is(ran, 0, 'the inert fallback context must not run a once factory');
    assert.is(result, null, 'once returns null on the inert fallback context');
}));
Suite.run();
