"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputQueueManager = void 0;
const node_readline_1 = __importDefault(require("node:readline"));
class InputQueueManager {
    stack = [];
    static instance = null;
    static rl = null;
    static keypressListenerSetup = false;
    lastKeypressWasTab = false;
    currentLine = "";
    pasteBuffer = [];
    pasteTimeout = null;
    PASTE_DELAY_MS = 10;
    historyIndex = -1;
    savedLineBeforeHistory = "";
    onNewEntry;
    constructor() {
        InputQueueManager.instance = this;
    }
    setOnNewEntry(callback) {
        this.onNewEntry = callback;
    }
    ensureRl() {
        if (InputQueueManager.rl)
            return InputQueueManager.rl;
        InputQueueManager.rl = node_readline_1.default.createInterface({
            input: process.stdin,
            output: process.stdout,
            terminal: true,
            historySize: 0,
            completer: (line) => [[], line],
        });
        InputQueueManager.rl.on("line", (line) => {
            const current = this.peek();
            if (!current)
                return;
            if (this.pasteTimeout) {
                this.pasteBuffer.push(line);
                clearTimeout(this.pasteTimeout);
                this.pasteTimeout = setTimeout(() => this.flushPasteBuffer(), this.PASTE_DELAY_MS);
                return;
            }
            this.pasteBuffer.push(line);
            this.pasteTimeout = setTimeout(() => this.flushPasteBuffer(), this.PASTE_DELAY_MS);
        });
        InputQueueManager.rl.on("close", () => {
            if (this.pasteTimeout) {
                clearTimeout(this.pasteTimeout);
                this.flushPasteBuffer();
                this.historyIndex = -1;
            }
        });
        InputQueueManager.rl.on("SIGINT", () => {
            if (this.stack.length > 0) {
                const cancelled = this.stack.pop();
                cancelled?.resolve("");
                this.currentLine = "";
                this.historyIndex = -1;
                this.savedLineBeforeHistory = "";
                this.renderTopOrClose();
                return;
            }
            this.close();
            process.exit(0);
        });
        if (!InputQueueManager.keypressListenerSetup) {
            InputQueueManager.keypressListenerSetup = true;
            node_readline_1.default.emitKeypressEvents(process.stdin);
            if (process.stdin.isTTY)
                process.stdin.setRawMode(true);
            process.stdin.on("keypress", (_str, key) => {
                const instance = InputQueueManager.instance;
                if (!instance)
                    return;
                if (key?.ctrl && key?.name === "c") {
                    if (instance.stack.length > 0) {
                        const cancelled = instance.stack.pop();
                        cancelled?.resolve("");
                        instance.currentLine = "";
                    }
                    instance.close();
                    process.exit(0);
                }
                if (!InputQueueManager.rl || instance.stack.length === 0)
                    return;
                instance.syncFromReadline();
                const exitsHistoryMode = key &&
                    (key.name === "return" ||
                        key.name === "enter" ||
                        key.name === "backspace" ||
                        (key.sequence &&
                            key.sequence.length === 1 &&
                            !key.ctrl &&
                            !key.meta));
                if (exitsHistoryMode && instance.historyIndex !== -1) {
                    instance.historyIndex = -1;
                    instance.savedLineBeforeHistory = "";
                }
                if (key?.name === "tab") {
                    instance.handleTabCompletion();
                    return;
                }
                instance.lastKeypressWasTab = false;
                if (key?.name === "up") {
                    const history = instance.getHistory();
                    if (history.length === 0)
                        return;
                    if (instance.historyIndex === -1) {
                        instance.savedLineBeforeHistory = instance.currentLine;
                    }
                    if (instance.historyIndex < history.length - 1) {
                        instance.historyIndex++;
                        const index = history.length - 1 - instance.historyIndex;
                        const next = history[index] ?? "";
                        instance.replaceLine(next);
                        instance.currentLine = next;
                    }
                    return;
                }
                if (key?.name === "down") {
                    const history = instance.getHistory();
                    if (history.length === 0)
                        return;
                    if (instance.historyIndex > 0) {
                        instance.historyIndex--;
                        const index = history.length - 1 - instance.historyIndex;
                        const next = history[index] ?? "";
                        instance.replaceLine(next);
                        instance.currentLine = next;
                        return;
                    }
                    if (instance.historyIndex === 0) {
                        instance.historyIndex = -1;
                        const restore = instance.savedLineBeforeHistory ?? "";
                        instance.savedLineBeforeHistory = "";
                        instance.replaceLine(restore);
                        instance.currentLine = restore;
                        return;
                    }
                    return;
                }
            });
        }
        return InputQueueManager.rl;
    }
    flushPasteBuffer() {
        if (this.pasteBuffer.length === 0)
            return;
        const answer = this.pasteBuffer.join("\n");
        this.pasteBuffer = [];
        this.pasteTimeout = null;
        const current = this.peek();
        if (!current)
            return;
        const resolved = this.stack.pop();
        resolved?.resolve(answer);
        if (answer && this.onNewEntry) {
            this.onNewEntry(answer);
        }
        this.currentLine = "";
        this.historyIndex = -1;
        this.savedLineBeforeHistory = "";
        this.renderTopOrClose();
    }
    async ask(question, options = [], history = []) {
        return new Promise((resolve) => {
            this.stack.push({ question, options, history, resolve });
            this.historyIndex = -1;
            const rl = this.ensureRl();
            this.syncFromReadline();
            this.render();
            this.replaceLine(this.currentLine);
            rl.prompt(true);
        });
    }
    peek() {
        return this.stack[this.stack.length - 1];
    }
    syncFromReadline() {
        if (!InputQueueManager.rl)
            return;
        this.currentLine = InputQueueManager.rl.line ?? "";
    }
    sanitizeHistoryEntry(value) {
        return value.replace(/[\r\n]+/g, " ").trim();
    }
    getHistory() {
        const current = this.peek();
        const history = current?.history ?? [];
        const out = [];
        for (const item of history) {
            const clean = this.sanitizeHistoryEntry(item);
            if (clean) {
                out.push(clean);
            }
        }
        return out;
    }
    handleTabCompletion() {
        const current = this.peek();
        const opts = current?.options ?? [];
        this.syncFromReadline();
        const line = this.currentLine;
        if (opts.length === 0) {
            this.lastKeypressWasTab = false;
            return;
        }
        const lastSpace = Math.max(line.lastIndexOf(" "), line.lastIndexOf("\t"));
        const word = line.slice(lastSpace + 1);
        const hits = opts.filter((c) => c.startsWith(word));
        let effectiveHits;
        let completionWord;
        if (hits.length > 0) {
            effectiveHits = hits;
            completionWord = this.longestCommonPrefix(effectiveHits);
        }
        else {
            const containsHits = opts.filter((c) => c.includes(word));
            effectiveHits = containsHits;
            if (containsHits.length > 0) {
                if (containsHits.length === 1) {
                    completionWord = containsHits[0];
                }
                else {
                    const suffixes = containsHits.map((c) => {
                        const idx = c.indexOf(word);
                        return c.slice(idx);
                    });
                    completionWord = this.longestCommonPrefix(suffixes);
                }
            }
            else {
                completionWord = word;
            }
        }
        if (effectiveHits.length === 0) {
            this.lastKeypressWasTab = false;
            return;
        }
        if (completionWord.length > word.length) {
            const before = line.slice(0, lastSpace + 1);
            const newLine = before + completionWord;
            this.replaceLine(newLine);
            this.currentLine = newLine;
            this.lastKeypressWasTab = false;
            return;
        }
        if (!this.lastKeypressWasTab) {
            this.lastKeypressWasTab = true;
            return;
        }
        this.lastKeypressWasTab = false;
        const columns = process.stdout.columns || 80;
        const maxWidth = Math.max(...effectiveHits.map((h) => h.length)) + 2;
        const numCols = Math.max(1, Math.floor(columns / maxWidth));
        const rows = [];
        for (let i = 0; i < effectiveHits.length; i += numCols) {
            const row = effectiveHits.slice(i, i + numCols);
            rows.push(row.map((h) => h.padEnd(maxWidth)).join(""));
        }
        const promptText = current.question;
        const inputText = this.currentLine;
        process.stdout.write("\r\n" + rows.join("\r\n") + "\r\n" + promptText + inputText);
        InputQueueManager.rl?.write(null, { ctrl: true, name: "u" });
        if (inputText)
            InputQueueManager.rl?.write(inputText);
    }
    render() {
        if (!InputQueueManager.rl)
            return;
        const current = this.peek();
        if (!current)
            return;
        InputQueueManager.rl.setPrompt(current.question);
        InputQueueManager.rl.prompt(true);
    }
    renderTopOrClose() {
        if (this.stack.length === 0) {
            this.close();
            return;
        }
        this.syncFromReadline();
        this.render();
        this.replaceLine(this.currentLine);
        InputQueueManager.rl?.prompt(true);
    }
    replaceLine(next) {
        if (!InputQueueManager.rl)
            return;
        const safe = this.sanitizeHistoryEntry(next);
        InputQueueManager.rl.write(null, { ctrl: true, name: "u" });
        if (safe)
            InputQueueManager.rl.write(safe);
    }
    longestCommonPrefix(items) {
        if (items.length === 0)
            return "";
        let prefix = items[0];
        for (let i = 1; i < items.length; i++) {
            const s = items[i];
            let j = 0;
            while (j < prefix.length && j < s.length && prefix[j] === s[j])
                j++;
            prefix = prefix.slice(0, j);
            if (!prefix)
                break;
        }
        return prefix;
    }
    close() {
        if (!InputQueueManager.rl)
            return;
        InputQueueManager.rl.close();
        InputQueueManager.rl = null;
        if (process.stdin.isTTY) {
            try {
                process.stdin.setRawMode(false);
            }
            catch {
            }
        }
    }
}
exports.InputQueueManager = InputQueueManager;
//# sourceMappingURL=InputQueueManager.js.map