import { TUI_KEYBINDINGS, KeybindingsManager as TuiKeybindingsManager, } from "@earendil-works/pi-tui";
import { existsSync, readFileSync } from "fs";
import { join } from "path";
import { getAgentDir } from "../config.js";
import { stripBom } from "../utils/text.js";
export function useWindowsKeybindings(platform = process.platform, env = process.env) {
    return platform === "win32" || (platform === "linux" && Boolean(env.WSL_DISTRO_NAME || env.WSL_INTEROP));
}
const windowsKeybindings = useWindowsKeybindings();
export const KEYBINDINGS = {
    ...TUI_KEYBINDINGS,
    "tui.editor.undo": {
        ...TUI_KEYBINDINGS["tui.editor.undo"],
        defaultKeys: process.platform === "win32" ? "ctrl+z" : windowsKeybindings ? "alt+z" : "ctrl+-",
    },
    "tui.altScreen.previousPrompt": {
        ...TUI_KEYBINDINGS["tui.altScreen.previousPrompt"],
        defaultKeys: windowsKeybindings ? "ctrl+up" : ["ctrl+shift+up", "ctrl+up"],
    },
    "tui.altScreen.nextPrompt": {
        ...TUI_KEYBINDINGS["tui.altScreen.nextPrompt"],
        defaultKeys: windowsKeybindings ? "ctrl+down" : ["ctrl+shift+down", "ctrl+down"],
    },
    "tui.altScreen.search": {
        ...TUI_KEYBINDINGS["tui.altScreen.search"],
        defaultKeys: windowsKeybindings ? "ctrl+f" : "ctrl+shift+f",
    },
    "app.interrupt": { defaultKeys: "escape", description: "Cancel or abort" },
    "app.clear": { defaultKeys: "ctrl+c", description: "Clear editor" },
    "app.exit": { defaultKeys: "ctrl+d", description: "Exit when editor is empty" },
    "app.suspend": {
        defaultKeys: process.platform === "win32" ? [] : "ctrl+z",
        description: "Suspend to background",
    },
    "app.thinking.cycle": {
        defaultKeys: "shift+tab",
        description: "Cycle thinking level",
    },
    "app.model.cycleForward": {
        defaultKeys: "ctrl+p",
        description: "Cycle to next model",
    },
    "app.model.cycleBackward": {
        defaultKeys: windowsKeybindings ? "alt+p" : "shift+ctrl+p",
        description: "Cycle to previous model",
    },
    "app.model.select": { defaultKeys: "ctrl+l", description: "Open model selector" },
    "app.tools.expand": { defaultKeys: "ctrl+o", description: "Toggle tool output" },
    "app.thinking.toggle": {
        defaultKeys: "ctrl+t",
        description: "Toggle thinking blocks",
    },
    "app.session.toggleNamedFilter": {
        defaultKeys: "ctrl+n",
        description: "Toggle named session filter",
    },
    "app.editor.external": {
        defaultKeys: "ctrl+g",
        description: "Open external editor",
    },
    "app.message.copy": {
        defaultKeys: "ctrl+x",
        description: "Copy message to clipboard",
    },
    "app.message.followUp": {
        defaultKeys: windowsKeybindings ? "ctrl+q" : "alt+enter",
        description: "Queue follow-up message",
    },
    "app.message.dequeue": {
        defaultKeys: windowsKeybindings ? "alt+q" : "alt+up",
        description: "Restore queued messages",
    },
    "app.clipboard.pasteImage": {
        defaultKeys: windowsKeybindings ? "alt+v" : "ctrl+v",
        description: "Paste image from clipboard (text fallback)",
    },
    "app.session.new": { defaultKeys: [], description: "Start a new session" },
    "app.session.tree": { defaultKeys: [], description: "Open session tree" },
    "app.session.fork": { defaultKeys: [], description: "Fork current session" },
    "app.session.resume": { defaultKeys: [], description: "Resume a session" },
    "app.tree.foldOrUp": {
        defaultKeys: process.platform === "darwin" ? ["alt+left", "ctrl+left"] : ["ctrl+left", "alt+left"],
        description: "Fold tree branch or move up",
    },
    "app.tree.unfoldOrDown": {
        defaultKeys: process.platform === "darwin" ? ["alt+right", "ctrl+right"] : ["ctrl+right", "alt+right"],
        description: "Unfold tree branch or move down",
    },
    "app.tree.editLabel": {
        defaultKeys: "shift+l",
        description: "Edit tree label",
    },
    "app.tree.toggleLabelTimestamp": {
        defaultKeys: "shift+t",
        description: "Toggle tree label timestamps",
    },
    "app.session.togglePath": {
        defaultKeys: "ctrl+p",
        description: "Toggle session path display",
    },
    "app.session.toggleSort": {
        defaultKeys: "ctrl+s",
        description: "Toggle session sort mode",
    },
    "app.session.rename": {
        defaultKeys: "ctrl+r",
        description: "Rename session",
    },
    "app.session.delete": {
        defaultKeys: "ctrl+d",
        description: "Delete session",
    },
    "app.session.deleteNoninvasive": {
        defaultKeys: "ctrl+backspace",
        description: "Delete session when query is empty",
    },
    "app.models.save": {
        defaultKeys: "ctrl+s",
        description: "Save model selection",
    },
    "app.models.enableAll": {
        defaultKeys: "ctrl+a",
        description: "Enable all models",
    },
    "app.models.clearAll": {
        defaultKeys: "ctrl+x",
        description: "Clear all models",
    },
    "app.models.toggleProvider": {
        defaultKeys: "ctrl+p",
        description: "Toggle all models for provider",
    },
    "app.models.reorderUp": {
        defaultKeys: "alt+up",
        description: "Move model up in order",
    },
    "app.models.reorderDown": {
        defaultKeys: "alt+down",
        description: "Move model down in order",
    },
    "app.tree.filter.default": {
        defaultKeys: "ctrl+d",
        description: "Tree filter: default view",
    },
    "app.tree.filter.noTools": {
        defaultKeys: "ctrl+t",
        description: "Tree filter: hide tool results",
    },
    "app.tree.filter.userOnly": {
        defaultKeys: "ctrl+u",
        description: "Tree filter: user messages only",
    },
    "app.tree.filter.labeledOnly": {
        defaultKeys: "ctrl+l",
        description: "Tree filter: labeled entries only",
    },
    "app.tree.filter.all": {
        defaultKeys: "ctrl+a",
        description: "Tree filter: show all entries",
    },
    "app.tree.filter.cycleForward": {
        defaultKeys: "ctrl+o",
        description: "Tree filter: cycle forward",
    },
    "app.tree.filter.cycleBackward": {
        defaultKeys: "shift+ctrl+o",
        description: "Tree filter: cycle backward",
    },
};
const KEYBINDING_NAME_MIGRATIONS = {
    cursorUp: "tui.editor.cursorUp",
    cursorDown: "tui.editor.cursorDown",
    cursorLeft: "tui.editor.cursorLeft",
    cursorRight: "tui.editor.cursorRight",
    cursorWordLeft: "tui.editor.cursorWordLeft",
    cursorWordRight: "tui.editor.cursorWordRight",
    cursorLineStart: "tui.editor.cursorLineStart",
    cursorLineEnd: "tui.editor.cursorLineEnd",
    jumpForward: "tui.editor.jumpForward",
    jumpBackward: "tui.editor.jumpBackward",
    pageUp: "tui.editor.pageUp",
    pageDown: "tui.editor.pageDown",
    deleteCharBackward: "tui.editor.deleteCharBackward",
    deleteCharForward: "tui.editor.deleteCharForward",
    deleteWordBackward: "tui.editor.deleteWordBackward",
    deleteWordForward: "tui.editor.deleteWordForward",
    deleteToLineStart: "tui.editor.deleteToLineStart",
    deleteToLineEnd: "tui.editor.deleteToLineEnd",
    yank: "tui.editor.yank",
    yankPop: "tui.editor.yankPop",
    undo: "tui.editor.undo",
    newLine: "tui.input.newLine",
    submit: "tui.input.submit",
    tab: "tui.input.tab",
    copy: "tui.input.copy",
    selectUp: "tui.select.up",
    selectDown: "tui.select.down",
    selectPageUp: "tui.select.pageUp",
    selectPageDown: "tui.select.pageDown",
    selectConfirm: "tui.select.confirm",
    selectCancel: "tui.select.cancel",
    interrupt: "app.interrupt",
    clear: "app.clear",
    exit: "app.exit",
    suspend: "app.suspend",
    cycleThinkingLevel: "app.thinking.cycle",
    cycleModelForward: "app.model.cycleForward",
    cycleModelBackward: "app.model.cycleBackward",
    selectModel: "app.model.select",
    expandTools: "app.tools.expand",
    toggleThinking: "app.thinking.toggle",
    toggleSessionNamedFilter: "app.session.toggleNamedFilter",
    externalEditor: "app.editor.external",
    followUp: "app.message.followUp",
    dequeue: "app.message.dequeue",
    pasteImage: "app.clipboard.pasteImage",
    newSession: "app.session.new",
    tree: "app.session.tree",
    fork: "app.session.fork",
    resume: "app.session.resume",
    treeFoldOrUp: "app.tree.foldOrUp",
    treeUnfoldOrDown: "app.tree.unfoldOrDown",
    treeEditLabel: "app.tree.editLabel",
    treeToggleLabelTimestamp: "app.tree.toggleLabelTimestamp",
    toggleSessionPath: "app.session.togglePath",
    toggleSessionSort: "app.session.toggleSort",
    renameSession: "app.session.rename",
    deleteSession: "app.session.delete",
    deleteSessionNoninvasive: "app.session.deleteNoninvasive",
};
function isLegacyKeybindingName(key) {
    return key in KEYBINDING_NAME_MIGRATIONS;
}
function toKeybindingsConfig(value) {
    const config = {};
    for (const [key, binding] of Object.entries(value)) {
        if (typeof binding === "string") {
            config[key] = binding;
            continue;
        }
        if (Array.isArray(binding) && binding.every((entry) => typeof entry === "string")) {
            config[key] = binding;
        }
    }
    return config;
}
export function migrateKeybindingsConfig(rawConfig) {
    const config = {};
    let migrated = false;
    for (const [key, value] of Object.entries(rawConfig)) {
        const nextKey = isLegacyKeybindingName(key) ? KEYBINDING_NAME_MIGRATIONS[key] : key;
        if (nextKey !== key) {
            migrated = true;
        }
        if (key !== nextKey && Object.hasOwn(rawConfig, nextKey)) {
            migrated = true;
            continue;
        }
        config[nextKey] = value;
    }
    return { config: orderKeybindingsConfig(config), migrated };
}
function orderKeybindingsConfig(config) {
    const ordered = {};
    for (const keybinding of Object.keys(KEYBINDINGS)) {
        if (Object.hasOwn(config, keybinding)) {
            ordered[keybinding] = config[keybinding];
        }
    }
    const extras = Object.keys(config)
        .filter((key) => !Object.hasOwn(ordered, key))
        .sort();
    for (const key of extras) {
        ordered[key] = config[key];
    }
    return ordered;
}
function loadRawConfig(path) {
    if (!existsSync(path))
        return undefined;
    try {
        const parsed = JSON.parse(stripBom(readFileSync(path, "utf-8")));
        if (typeof parsed !== "object" || parsed === null)
            return undefined;
        return parsed;
    }
    catch {
        return undefined;
    }
}
export class KeybindingsManager extends TuiKeybindingsManager {
    configPath;
    constructor(userBindings = {}, configPath) {
        super(KEYBINDINGS, userBindings);
        this.configPath = configPath;
    }
    static create(agentDir = getAgentDir()) {
        const configPath = join(agentDir, "keybindings.json");
        const userBindings = KeybindingsManager.loadFromFile(configPath);
        return new KeybindingsManager(userBindings, configPath);
    }
    reload() {
        if (!this.configPath)
            return;
        this.setUserBindings(KeybindingsManager.loadFromFile(this.configPath));
    }
    getEffectiveConfig() {
        return this.getResolvedBindings();
    }
    static loadFromFile(path) {
        const rawConfig = loadRawConfig(path);
        if (!rawConfig)
            return {};
        return toKeybindingsConfig(migrateKeybindingsConfig(rawConfig).config);
    }
}
//# sourceMappingURL=keybindings.js.map