import { __awaiter, __decorate } from "tslib";
import { customElement, GenesisElement, html, observable } from '@genesislcap/web-core';
import { agenticActivityBus } from '../../channel/ai-activity-bus';
/**
 * App-shell component that owns the pop-out/pop-in lifecycle for the AI assistant bubble.
 *
 * @remarks
 * Place this in the persistent app shell, wrapping a `foundation-ai-chat-bubble` that
 * contains an AI assistant element in the `dialog-content` slot.
 *
 * GENC-1351 (Option A — single element): rather than cloning a second assistant to
 * dock, this manager **moves the one real element** between the bubble and the page
 * layout. One connected instance means no dual-view coordination (no shared-driver
 * unwire/rewire, host election, or duplicated side-effects); the session survives the
 * move because the driver/store/persister live in module-level registries keyed by the
 * element's identity.
 *
 * Pages that support docking call `aiPopoutManager.registerDockProvider()` on mount
 * and `aiPopoutManager.deregisterDockProvider()` on unmount.
 *
 * @example
 * ```html
 * <foundation-ai-popout-manager>
 *   <foundation-ai-chat-bubble title="My Assistant">
 *     <my-assistant slot="dialog-content"></my-assistant>
 *   </foundation-ai-chat-bubble>
 * </foundation-ai-popout-manager>
 * ```
 *
 * @beta
 */
let FoundationAiPopoutManager = class FoundationAiPopoutManager extends GenesisElement {
    constructor() {
        super(...arguments);
        /** True when a dock provider is registered — controls expand button visibility. */
        this.canDock = false;
        /**
         * The single assistant element. Captured while it's in the bubble slot and held
         * across the move (it's the same instance whether docked or in the bubble), so
         * pop-in can re-home it even though it's no longer a child of this manager.
         */
        this.assistantEl = null;
        this.dockProvider = null;
        this.isDocked = false;
    }
    connectedCallback() {
        super.connectedCallback();
        // oxlint-disable-next-line typescript/no-this-alias -- module-level singleton, not a local alias
        _aiPopoutManager = this;
        this.assistantEl = this.findAssistant();
        const unsubPopout = agenticActivityBus.subscribe('chat-popout', () => __awaiter(this, void 0, void 0, function* () {
            var _a;
            if (this.isDocked || !this.dockProvider)
                return;
            const el = ((_a = this.assistantEl) !== null && _a !== void 0 ? _a : (this.assistantEl = this.findAssistant()));
            if (!el)
                return;
            this.isDocked = true;
            _aiAssistantDocked = true;
            this.syncBubbleVisibility();
            // Reflect the new location on the assistant so its header shows the "collapse"
            // affordance. This is now purely cosmetic — the element stays wired across the
            // move, so an async mode-forward by a wrapper element can't break it.
            el.setAttribute('popout-mode', 'collapse');
            // Hand the ONE real element to the page; the provider moves it into its layout.
            yield this.dockProvider.onDock(el);
        }));
        const unsubPopin = agenticActivityBus.subscribe('chat-popin', () => __awaiter(this, void 0, void 0, function* () {
            var _a;
            if (!this.isDocked)
                return;
            this.isDocked = false;
            _aiAssistantDocked = false;
            // Re-home the assistant into the bubble BEFORE the provider tears down its
            // layout slot — its removeItems (or equivalent) would otherwise destroy the
            // moved element.
            const bubble = this.querySelector('foundation-ai-chat-bubble');
            if (this.assistantEl && bubble) {
                this.assistantEl.setAttribute('popout-mode', 'expand');
                this.assistantEl.setAttribute('slot', 'dialog-content');
                bubble.appendChild(this.assistantEl);
            }
            this.syncBubbleVisibility();
            yield ((_a = this.dockProvider) === null || _a === void 0 ? void 0 : _a.onUndock());
        }));
        this.unsubBus = () => {
            unsubPopout();
            unsubPopin();
        };
        this.syncBubbleVisibility();
    }
    disconnectedCallback() {
        var _a;
        super.disconnectedCallback();
        (_a = this.unsubBus) === null || _a === void 0 ? void 0 : _a.call(this);
        this.unsubBus = undefined;
        _aiPopoutManager = undefined;
    }
    /** Locate the assistant element currently slotted into the bubble. */
    findAssistant() {
        var _a;
        const bubble = this.querySelector('foundation-ai-chat-bubble');
        return (_a = bubble === null || bubble === void 0 ? void 0 : bubble.querySelector('[slot="dialog-content"]')) !== null && _a !== void 0 ? _a : null;
    }
    /**
     * Register an externally-created assistant element and its docked state. For
     * single-element hosts that create the assistant directly in a layout pane (rather
     * than statically in the bubble), so the manager tracks the one element, whether it's
     * currently docked (for pop-in re-homing), reflects the right `popout-mode` on it
     * (drives the header button), and hides the empty bubble.
     */
    adoptAssistant(el, docked) {
        this.assistantEl = el;
        this.isDocked = docked;
        _aiAssistantDocked = docked;
        el.setAttribute('popout-mode', docked ? 'collapse' : 'expand');
        this.syncBubbleVisibility();
    }
    /** Hide the floating bubble unless it currently contains the assistant. */
    syncBubbleVisibility() {
        const bubble = this.querySelector('foundation-ai-chat-bubble');
        if (!bubble)
            return;
        const hasAssistant = !!bubble.querySelector('[slot="dialog-content"]');
        bubble.style.display = this.isDocked || !hasAssistant ? 'none' : '';
    }
    canDockChanged() {
        var _a;
        const el = ((_a = this.assistantEl) !== null && _a !== void 0 ? _a : (this.assistantEl = this.findAssistant()));
        if (this.canDock) {
            el === null || el === void 0 ? void 0 : el.setAttribute('popout-mode', this.isDocked ? 'collapse' : 'expand');
        }
        else {
            el === null || el === void 0 ? void 0 : el.removeAttribute('popout-mode');
        }
    }
    registerDockProvider(provider) {
        this.dockProvider = provider;
        this.canDock = true;
    }
    deregisterDockProvider() {
        this.isDocked = false;
        _aiAssistantDocked = false;
        this.dockProvider = null;
        this.canDock = false;
    }
    /**
     * If the assistant is currently docked, collapses it back into the bubble.
     * Await this in `onBeforeNavButtonClick` to ensure cleanup before navigation.
     */
    collapseIfDocked() {
        if (!this.isDocked || !this.dockProvider)
            return Promise.resolve();
        this.dockProvider.initiateCollapse();
        return Promise.resolve();
    }
};
__decorate([
    observable
], FoundationAiPopoutManager.prototype, "canDock", void 0);
FoundationAiPopoutManager = __decorate([
    customElement({
        name: 'foundation-ai-popout-manager',
        template: html `
    <slot></slot>
  `,
    })
], FoundationAiPopoutManager);
export { FoundationAiPopoutManager };
let _aiPopoutManager;
/** Whether the assistant is currently docked in the layout panel (vs bubble-only). */
let _aiAssistantDocked = false;
/** True when the assistant is active in the layout panel (docked) rather than the bubble. */
export function isAiAssistantDocked() {
    return _aiAssistantDocked;
}
/**
 * Returns the active `FoundationAiPopoutManager` instance, or `undefined` if none is mounted.
 * Import this in pages to call `registerDockProvider` / `deregisterDockProvider`.
 *
 * @beta
 */
export function getAiPopoutManager() {
    return _aiPopoutManager;
}
