import { getOAuthProviders } from "@mariozechner/pi-ai/oauth";
import { Container, getKeybindings, Input, Spacer, Text } from "@mariozechner/pi-tui";
import { exec } from "child_process";
import { theme } from "../theme/theme.js";
import { DynamicBorder } from "./dynamic-border.js";
import { keyHint } from "./keybinding-hints.js";
/**
 * Login dialog component - replaces editor during OAuth login flow
 */
export class LoginDialogComponent extends Container {
    onComplete;
    contentContainer;
    input;
    tui;
    abortController = new AbortController();
    inputResolver;
    inputRejecter;
    // Focusable implementation - propagate to input for IME cursor positioning
    _focused = false;
    get focused() {
        return this._focused;
    }
    set focused(value) {
        this._focused = value;
        this.input.focused = value;
    }
    constructor(tui, providerId, onComplete, providerNameOverride, titleOverride) {
        super();
        this.onComplete = onComplete;
        this.tui = tui;
        const providerInfo = getOAuthProviders().find((p) => p.id === providerId);
        const providerName = providerNameOverride || providerInfo?.name || providerId;
        const title = titleOverride ?? `Login to ${providerName}`;
        // Top border
        this.addChild(new DynamicBorder());
        // Title
        this.addChild(new Text(theme.fg("accent", theme.bold(title)), 1, 0));
        // Dynamic content area
        this.contentContainer = new Container();
        this.addChild(this.contentContainer);
        // Input (always present, used when needed)
        this.input = new Input();
        this.input.onSubmit = () => {
            if (this.inputResolver) {
                this.inputResolver(this.input.getValue());
                this.inputResolver = undefined;
                this.inputRejecter = undefined;
            }
        };
        this.input.onEscape = () => {
            this.cancel();
        };
        // Bottom border
        this.addChild(new DynamicBorder());
    }
    get signal() {
        return this.abortController.signal;
    }
    cancel() {
        this.abortController.abort();
        if (this.inputRejecter) {
            this.inputRejecter(new Error("Login cancelled"));
            this.inputResolver = undefined;
            this.inputRejecter = undefined;
        }
        this.onComplete(false, "Login cancelled");
    }
    /**
     * Called by onAuth callback - show URL and optional instructions
     */
    showAuth(url, instructions) {
        this.contentContainer.clear();
        this.contentContainer.addChild(new Spacer(1));
        const linkedUrl = `\x1b]8;;${url}\x07${url}\x1b]8;;\x07`;
        this.contentContainer.addChild(new Text(theme.fg("accent", linkedUrl), 1, 0));
        const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
        const hyperlink = `\x1b]8;;${url}\x07${clickHint}\x1b]8;;\x07`;
        this.contentContainer.addChild(new Text(theme.fg("dim", hyperlink), 1, 0));
        if (instructions) {
            this.contentContainer.addChild(new Spacer(1));
            this.contentContainer.addChild(new Text(theme.fg("warning", instructions), 1, 0));
        }
        // Try to open browser
        const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
        exec(`${openCmd} "${url}"`);
        this.tui.requestRender();
    }
    /**
     * Show input for manual code/URL entry (for callback server providers)
     */
    showManualInput(prompt) {
        this.contentContainer.addChild(new Spacer(1));
        this.contentContainer.addChild(new Text(theme.fg("dim", prompt), 1, 0));
        this.contentContainer.addChild(this.input);
        this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to cancel")})`, 1, 0));
        this.tui.requestRender();
        return new Promise((resolve, reject) => {
            this.inputResolver = resolve;
            this.inputRejecter = reject;
        });
    }
    /**
     * Called by onPrompt callback - show prompt and wait for input
     * Note: Does NOT clear content, appends to existing (preserves URL from showAuth)
     */
    showPrompt(message, placeholder) {
        this.contentContainer.addChild(new Spacer(1));
        this.contentContainer.addChild(new Text(theme.fg("text", message), 1, 0));
        if (placeholder) {
            this.contentContainer.addChild(new Text(theme.fg("dim", `e.g., ${placeholder}`), 1, 0));
        }
        this.contentContainer.addChild(this.input);
        this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to cancel,")} ${keyHint("tui.select.confirm", "to submit")})`, 1, 0));
        this.input.setValue("");
        this.tui.requestRender();
        return new Promise((resolve, reject) => {
            this.inputResolver = resolve;
            this.inputRejecter = reject;
        });
    }
    /**
     * Show informational text without prompting for input.
     */
    showInfo(lines) {
        this.contentContainer.clear();
        this.contentContainer.addChild(new Spacer(1));
        for (const line of lines) {
            this.contentContainer.addChild(new Text(line, 1, 0));
        }
        this.contentContainer.addChild(new Spacer(1));
        this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to close")})`, 1, 0));
        this.tui.requestRender();
    }
    /**
     * Show waiting message (for polling flows like GitHub Copilot)
     */
    showWaiting(message) {
        this.contentContainer.addChild(new Spacer(1));
        this.contentContainer.addChild(new Text(theme.fg("dim", message), 1, 0));
        this.contentContainer.addChild(new Text(`(${keyHint("tui.select.cancel", "to cancel")})`, 1, 0));
        this.tui.requestRender();
    }
    /**
     * Called by onProgress callback
     */
    showProgress(message) {
        this.contentContainer.addChild(new Text(theme.fg("dim", message), 1, 0));
        this.tui.requestRender();
    }
    handleInput(data) {
        const kb = getKeybindings();
        if (kb.matches(data, "tui.select.cancel")) {
            this.cancel();
            return;
        }
        // Pass to input
        this.input.handleInput(data);
    }
}
//# sourceMappingURL=login-dialog.js.map