import * as crypto from "node:crypto";
import { theme } from "../interactive/theme/theme.js";
function createDialogPromise({ output, pendingExtensionRequests, dialogOptions, defaultValue, request, parseResponse, }) {
    if (dialogOptions?.signal?.aborted)
        return Promise.resolve(defaultValue);
    const id = crypto.randomUUID();
    return new Promise((resolve, reject) => {
        let timeoutId;
        const cleanup = () => {
            if (timeoutId)
                clearTimeout(timeoutId);
            dialogOptions?.signal?.removeEventListener("abort", onAbort);
            pendingExtensionRequests.delete(id);
        };
        const onAbort = () => {
            cleanup();
            resolve(defaultValue);
        };
        dialogOptions?.signal?.addEventListener("abort", onAbort, { once: true });
        if (dialogOptions?.timeout) {
            timeoutId = setTimeout(() => {
                cleanup();
                resolve(defaultValue);
            }, dialogOptions.timeout);
        }
        pendingExtensionRequests.set(id, {
            resolve: (response) => {
                cleanup();
                resolve(parseResponse(response));
            },
            reject,
        });
        output({ type: "extension_ui_request", id, ...request });
    });
}
function emitExtensionUIRequest(output, request) {
    output({ type: "extension_ui_request", id: crypto.randomUUID(), ...request });
}
export function createRpcExtensionUIContext({ output, pendingExtensionRequests, customUi, sessionPicker, inputForm, }) {
    const unsupportedWarnings = new Set();
    let toolsExpanded = false;
    const warnUnsupported = (method) => {
        if (!customUi || unsupportedWarnings.has(method))
            return;
        unsupportedWarnings.add(method);
        emitExtensionUIRequest(output, {
            method: "notify",
            message: `${method} is unavailable in isolated interactive mode because it requires a synchronous host callback`,
            notifyType: "warning",
        });
    };
    return {
        select: (title, options, opts) => createDialogPromise({
            output,
            pendingExtensionRequests,
            dialogOptions: opts,
            defaultValue: undefined,
            request: { method: "select", title, options, timeout: opts?.timeout },
            parseResponse: (response) => "cancelled" in response && response.cancelled ? undefined : "value" in response ? response.value : undefined,
        }),
        confirm: (title, message, opts) => createDialogPromise({
            output,
            pendingExtensionRequests,
            dialogOptions: opts,
            defaultValue: false,
            request: { method: "confirm", title, message, timeout: opts?.timeout },
            parseResponse: (response) => "cancelled" in response && response.cancelled ? false : "confirmed" in response ? response.confirmed : false,
        }),
        input: (title, placeholder, opts) => createDialogPromise({
            output,
            pendingExtensionRequests,
            dialogOptions: opts,
            defaultValue: undefined,
            request: { method: "input", title, placeholder, timeout: opts?.timeout },
            parseResponse: (response) => "cancelled" in response && response.cancelled ? undefined : "value" in response ? response.value : undefined,
        }),
        notify(message, type) {
            emitExtensionUIRequest(output, { method: "notify", message, notifyType: type });
        },
        requestRender() { customUi?.requestRender(); },
        getHostCustomUiState: () => customUi?.getHostCustomUiState() ?? {
            blockingInlineCustomUiDepth: 0,
            blockingInlineCustomUiActive: false,
        },
        onHostCustomUiStateChange: (listener) => customUi?.onHostCustomUiStateChange(listener) ?? (() => { }),
        focusHostInlineCustomUi: () => customUi?.focusHostInlineCustomUi() ?? false,
        onTerminalInput() {
            warnUnsupported("ctx.ui.onTerminalInput");
            return () => { };
        },
        setStatus(key, text) {
            emitExtensionUIRequest(output, { method: "setStatus", statusKey: key, statusText: text });
        },
        setWorkingMessage(_message) {
            // Working message not supported in RPC mode - requires TUI loader access
        },
        setWorkingVisible(_visible) {
            // Working visibility not supported in RPC mode - requires TUI loader access
        },
        setWorkingIndicator(_options) {
            // Working indicator customization not supported in RPC mode - requires TUI loader access
        },
        setHiddenThinkingLabel(_label) {
            // Hidden thinking label not supported in RPC mode - requires TUI message rendering access
        },
        setWidget(key, content, options) {
            if (content === undefined) {
                customUi?.setWidget(key, undefined, options?.placement);
                emitExtensionUIRequest(output, {
                    method: "setWidget", widgetKey: key, widgetLines: undefined, widgetPlacement: options?.placement,
                });
                return;
            }
            if (Array.isArray(content)) {
                emitExtensionUIRequest(output, {
                    method: "setWidget", widgetKey: key, widgetLines: content, widgetPlacement: options?.placement,
                });
                return;
            }
            if (customUi && typeof content === "function") {
                customUi.setWidget(key, content, options?.placement);
                return;
            }
            warnUnsupported("component-factory widgets");
        },
        setFooter() { warnUnsupported("ctx.ui.setFooter"); },
        setHeader() { warnUnsupported("ctx.ui.setHeader"); },
        setTitle(title) {
            emitExtensionUIRequest(output, { method: "setTitle", title });
        },
        custom: (factory, options) => customUi
            ? customUi.custom(factory, options)
            : Promise.resolve(undefined),
        // Exposed in the isolated engine child, where the terminal host mounts
        // the real session selector natively so picker navigation never crosses
        // the process boundary. Absent in plain headless RPC (no interactive
        // host); callers must fail with an actionable error, not degrade.
        ...(sessionPicker ? { hostSessionPicker: (request) => sessionPicker.open(request) } : {}),
        ...(inputForm ? { hostInputForm: (request) => inputForm.open(request) } : {}),
        pasteToEditor(text) {
            // Paste handling not supported in RPC mode - falls back to setEditorText
            this.setEditorText(text);
        },
        setEditorText(text) {
            emitExtensionUIRequest(output, { method: "set_editor_text", text });
        },
        getEditorText() {
            warnUnsupported("ctx.ui.getEditorText");
            return "";
        },
        async editor(title, prefill) {
            const id = crypto.randomUUID();
            return new Promise((resolve, reject) => {
                pendingExtensionRequests.set(id, {
                    resolve: (response) => {
                        if ("cancelled" in response && response.cancelled) {
                            resolve(undefined);
                        }
                        else if ("value" in response) {
                            resolve(response.value);
                        }
                        else {
                            resolve(undefined);
                        }
                    },
                    reject,
                });
                output({ type: "extension_ui_request", id, method: "editor", title, prefill });
            });
        },
        addAutocompleteProvider() { warnUnsupported("ctx.ui.addAutocompleteProvider"); },
        setEditorComponent() { warnUnsupported("ctx.ui.setEditorComponent"); },
        getEditorComponent() {
            // Custom editor components not supported in RPC mode
            return undefined;
        },
        getFooterDataProvider() {
            return {
                getGitBranch: () => null,
                getExtensionStatuses: () => new Map(),
                getAvailableProviderCount: () => 1,
                onBranchChange: () => () => { },
            };
        },
        get theme() {
            return theme;
        },
        getAllThemes() {
            return [];
        },
        getTheme(_name) {
            return undefined;
        },
        setTheme(_theme) {
            // Theme switching not supported in RPC mode
            return { success: false, error: "Theme switching not supported in RPC mode" };
        },
        getToolsExpanded() {
            return toolsExpanded;
        },
        setToolsExpanded(expanded) {
            toolsExpanded = expanded;
            customUi?.requestRender();
        },
        getChatRenderSettings() {
            return {
                hideThinkingBlock: false,
                hiddenThinkingLabel: "Thinking...",
                toolOutputExpanded: toolsExpanded,
                showImages: false,
                imageWidthCells: 60,
                getToolDefinition: () => undefined,
                getCustomMessageRenderer: () => undefined,
            };
        },
    };
}
//# sourceMappingURL=rpc-extension-ui.js.map