import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { dirname, join } from "node:path";
const THREADWELL_WEZTERM_BLOCK_START = "-- >>> Threadwell recommended tweak: keyboard mappings";
const THREADWELL_WEZTERM_BLOCK_END = "-- <<< Threadwell recommended tweak: keyboard mappings";
const LEGACY_THREADWELL_WEZTERM_BLOCK_START = "-- >>> Threadwell recommended tweak: Shift+Enter newline";
const LEGACY_THREADWELL_WEZTERM_BLOCK_END = "-- <<< Threadwell recommended tweak: Shift+Enter newline";
function escapeRegExp(value) {
    return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
function candidateWezTermConfigPaths() {
    const home = homedir();
    return [join(home, ".wezterm.lua"), join(home, ".config", "wezterm", "wezterm.lua")];
}
function selectWezTermConfigPath() {
    const candidates = candidateWezTermConfigPaths();
    return candidates.find((path) => existsSync(path)) ?? candidates[0];
}
function candidateWindowsTerminalConfigPaths() {
    const localAppData = process.env.LOCALAPPDATA;
    if (!localAppData)
        return [];
    return [
        join(localAppData, "Packages", "Microsoft.WindowsTerminal_8wekyb3d8bbwe", "LocalState", "settings.json"),
        join(localAppData, "Packages", "Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe", "LocalState", "settings.json"),
        join(localAppData, "Microsoft", "Windows Terminal", "settings.json"),
    ];
}
function selectWindowsTerminalConfigPath() {
    const candidates = candidateWindowsTerminalConfigPaths();
    return candidates.find((path) => existsSync(path)) ?? candidates[0];
}
function wezTermEntryLines(tweak) {
    switch (tweak) {
        case "wezterm-shift-enter":
            return [
                "{",
                "\tkey = 'Enter',",
                "\tmods = 'SHIFT',",
                "\taction = wezterm.action.SendString('\\x1b[13;2u'),",
                "},",
            ];
        case "wezterm-ctrl-word-delete":
            return [
                "{",
                "\tkey = 'Backspace',",
                "\tmods = 'CTRL',",
                "\taction = wezterm.action.SendString('\\x1b[127;5u'),",
                "},",
                "{",
                "\tkey = 'Delete',",
                "\tmods = 'CTRL',",
                "\taction = wezterm.action.SendString('\\x1b[3;5~'),",
                "},",
            ];
    }
}
function detectInstalledWezTermTweaks(content) {
    const installed = new Set();
    if (content.includes("\\x1b[13;2u"))
        installed.add("wezterm-shift-enter");
    if (content.includes("\\x1b[127;5u") || content.includes("\\x1b[3;5~")) {
        installed.add("wezterm-ctrl-word-delete");
    }
    return installed;
}
function buildWezTermConfigBlock(tweaks) {
    const lines = [THREADWELL_WEZTERM_BLOCK_START, "config.keys = config.keys or {}"];
    for (const tweak of tweaks) {
        const entries = wezTermEntryLines(tweak);
        let current = [];
        for (const line of entries) {
            current.push(line);
            if (line === "},") {
                lines.push("table.insert(config.keys, {");
                lines.push(...current.slice(1, -1));
                lines.push("})");
                current = [];
            }
        }
    }
    lines.push(THREADWELL_WEZTERM_BLOCK_END);
    return lines.join("\n");
}
function buildWezTermTableFieldsBlock(tweaks) {
    const entries = [...tweaks].flatMap((tweak) => wezTermEntryLines(tweak).map((line) => `\t\t${line}`));
    return [THREADWELL_WEZTERM_BLOCK_START, "\tkeys = {", ...entries, "\t},", THREADWELL_WEZTERM_BLOCK_END].join("\n");
}
function threadwellWezTermBlockPattern() {
    const current = `${escapeRegExp(THREADWELL_WEZTERM_BLOCK_START)}[\\s\\S]*?${escapeRegExp(THREADWELL_WEZTERM_BLOCK_END)}`;
    const legacy = `${escapeRegExp(LEGACY_THREADWELL_WEZTERM_BLOCK_START)}[\\s\\S]*?${escapeRegExp(LEGACY_THREADWELL_WEZTERM_BLOCK_END)}`;
    return new RegExp(`${current}|${legacy}`, "u");
}
function getWezTermTweaksStatus() {
    const path = selectWezTermConfigPath();
    if (!existsSync(path)) {
        return { path, installed: [], hasThreadwellBlock: false };
    }
    const content = readFileSync(path, "utf-8");
    return {
        path,
        installed: [...detectInstalledWezTermTweaks(content)],
        hasThreadwellBlock: threadwellWezTermBlockPattern().test(content),
    };
}
function createDefaultWezTermConfig(path, tweaks) {
    mkdirSync(dirname(path), { recursive: true });
    const content = [
        "local wezterm = require 'wezterm'",
        "local config = wezterm.config_builder()",
        "",
        buildWezTermConfigBlock(tweaks),
        "",
        "return config",
        "",
    ].join("\n");
    writeFileSync(path, content, "utf-8");
    return { path, changed: true, message: "Created WezTerm config with Threadwell terminal tweaks" };
}
function applyWezTermTweaks(requestedTweaks) {
    const path = selectWezTermConfigPath();
    const requested = new Set(requestedTweaks);
    if (!existsSync(path)) {
        return createDefaultWezTermConfig(path, requested);
    }
    const original = readFileSync(path, "utf-8");
    const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
    const backupPath = `${path}.threadwell-backup-${timestamp}`;
    const blockPattern = threadwellWezTermBlockPattern();
    const hasConfigReturn = /(^|\n)(\s*)return\s+config\b[^\n]*(?=\n|$)/u.test(original);
    const installed = detectInstalledWezTermTweaks(original);
    for (const tweak of requested)
        installed.add(tweak);
    const replacement = hasConfigReturn ? buildWezTermConfigBlock(installed) : buildWezTermTableFieldsBlock(installed);
    if (blockPattern.test(original)) {
        const updated = original.replace(blockPattern, replacement);
        if (updated === original)
            return { path, changed: false, message: "Threadwell WezTerm terminal tweaks are already installed" };
        copyFileSync(path, backupPath);
        writeFileSync(path, updated, "utf-8");
        return { path, changed: true, backupPath, message: "Updated WezTerm terminal tweaks" };
    }
    const returnConfigPattern = /(^|\n)(\s*)return\s+config\b[^\n]*(?=\n|$)/gu;
    const matches = [...original.matchAll(returnConfigPattern)];
    const lastReturn = matches.at(-1);
    if (lastReturn?.index !== undefined) {
        copyFileSync(path, backupPath);
        const insertAt = lastReturn.index + (lastReturn[1] === "\n" ? 1 : 0);
        const updated = `${original.slice(0, insertAt)}${replacement}\n\n${original.slice(insertAt)}`;
        writeFileSync(path, updated, "utf-8");
        return { path, changed: true, backupPath, message: "Installed WezTerm terminal tweaks" };
    }
    const returnTablePattern = /(^|\n)(\s*)return\s*\{/u;
    const returnTable = returnTablePattern.exec(original);
    if (!returnTable || returnTable.index === undefined) {
        return {
            path,
            changed: false,
            message: "Could not safely patch WezTerm config: expected `return config` or `return {`",
        };
    }
    if (/\bkeys\s*=/u.test(original)) {
        return {
            path,
            changed: false,
            message: "Could not safely patch table-style WezTerm config: keys already exists",
        };
    }
    copyFileSync(path, backupPath);
    const insertAt = returnTable.index + returnTable[0].length;
    const updated = `${original.slice(0, insertAt)}\n${replacement}\n${original.slice(insertAt)}`;
    writeFileSync(path, updated, "utf-8");
    return { path, changed: true, backupPath, message: "Installed WezTerm terminal tweaks" };
}
function stripJsonComments(input) {
    let output = "";
    let inString = false;
    let escaped = false;
    let inLineComment = false;
    let inBlockComment = false;
    for (let index = 0; index < input.length; index++) {
        const char = input[index];
        const next = input[index + 1];
        if (inLineComment) {
            if (char === "\n") {
                inLineComment = false;
                output += char;
            }
            continue;
        }
        if (inBlockComment) {
            if (char === "*" && next === "/") {
                inBlockComment = false;
                index++;
            }
            continue;
        }
        if (inString) {
            output += char;
            if (escaped)
                escaped = false;
            else if (char === "\\")
                escaped = true;
            else if (char === '"')
                inString = false;
            continue;
        }
        if (char === '"') {
            inString = true;
            output += char;
            continue;
        }
        if (char === "/" && next === "/") {
            inLineComment = true;
            index++;
            continue;
        }
        if (char === "/" && next === "*") {
            inBlockComment = true;
            index++;
            continue;
        }
        output += char;
    }
    return output;
}
function parseWindowsTerminalSettings(content) {
    try {
        const parsed = JSON.parse(stripJsonComments(content));
        if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
            return undefined;
        return parsed;
    }
    catch {
        return undefined;
    }
}
function windowsTerminalInputForTweak(tweak) {
    switch (tweak) {
        case "windows-terminal-shift-enter":
            return "\u001b[13;2u";
        case "windows-terminal-alt-enter":
            return "\u001b[13;3u";
        case "windows-terminal-ctrl-v":
            return "\u0016";
    }
}
function windowsTerminalKeysForTweak(tweak) {
    switch (tweak) {
        case "windows-terminal-shift-enter":
            return "shift+enter";
        case "windows-terminal-alt-enter":
            return "alt+enter";
        case "windows-terminal-ctrl-v":
            return "ctrl+v";
    }
}
function windowsTerminalActionIdForTweak(tweak) {
    switch (tweak) {
        case "windows-terminal-shift-enter":
            return "Threadwell.SendInput.ShiftEnter";
        case "windows-terminal-alt-enter":
            return "Threadwell.SendInput.AltEnter";
        case "windows-terminal-ctrl-v":
            return "Threadwell.SendInput.CtrlV";
    }
}
function createWindowsTerminalAction(tweak) {
    return {
        command: { action: "sendInput", input: windowsTerminalInputForTweak(tweak) },
        id: windowsTerminalActionIdForTweak(tweak),
    };
}
function createWindowsTerminalKeybinding(tweak) {
    return {
        id: windowsTerminalActionIdForTweak(tweak),
        keys: windowsTerminalKeysForTweak(tweak),
    };
}
function getWindowsTerminalActionInput(action) {
    if (typeof action.command !== "object" || action.command === null)
        return undefined;
    const command = action.command;
    if (command.action !== "sendInput" || typeof command.input !== "string")
        return undefined;
    return command.input;
}
function detectInstalledWindowsTerminalTweaks(settings) {
    const installed = new Set();
    const actionInputById = new Map();
    for (const action of settings.actions ?? []) {
        const input = getWindowsTerminalActionInput(action);
        if (input && typeof action.id === "string")
            actionInputById.set(action.id, input);
        const keys = typeof action.keys === "string" ? action.keys.toLowerCase() : undefined;
        if (keys === "shift+enter" && input === "\u001b[13;2u")
            installed.add("windows-terminal-shift-enter");
        if (keys === "alt+enter" && input === "\u001b[13;3u")
            installed.add("windows-terminal-alt-enter");
        if (keys === "ctrl+v" && input === "\u0016")
            installed.add("windows-terminal-ctrl-v");
    }
    for (const keybinding of settings.keybindings ?? []) {
        const keys = typeof keybinding.keys === "string" ? keybinding.keys.toLowerCase() : undefined;
        const input = typeof keybinding.id === "string" ? actionInputById.get(keybinding.id) : undefined;
        if (keys === "shift+enter" && input === "\u001b[13;2u")
            installed.add("windows-terminal-shift-enter");
        if (keys === "alt+enter" && input === "\u001b[13;3u")
            installed.add("windows-terminal-alt-enter");
        if (keys === "ctrl+v" && input === "\u0016")
            installed.add("windows-terminal-ctrl-v");
    }
    return installed;
}
function getWindowsTerminalTweaksStatus() {
    const path = selectWindowsTerminalConfigPath();
    if (!path || !existsSync(path)) {
        return { path: path ?? "", installed: [], hasThreadwellBlock: false };
    }
    const settings = parseWindowsTerminalSettings(readFileSync(path, "utf-8"));
    if (!settings)
        return { path, installed: [], hasThreadwellBlock: false };
    return { path, installed: [...detectInstalledWindowsTerminalTweaks(settings)], hasThreadwellBlock: false };
}
function applyWindowsTerminalTweaks(requestedTweaks) {
    const path = selectWindowsTerminalConfigPath();
    if (!path) {
        return { path: "", changed: false, message: "Could not find LOCALAPPDATA for Windows Terminal settings" };
    }
    if (!existsSync(path)) {
        return { path, changed: false, message: "Windows Terminal settings.json was not found" };
    }
    const original = readFileSync(path, "utf-8");
    const settings = parseWindowsTerminalSettings(original);
    if (!settings) {
        return { path, changed: false, message: "Could not parse Windows Terminal settings.json safely" };
    }
    const actions = Array.isArray(settings.actions) ? [...settings.actions] : [];
    const keybindings = Array.isArray(settings.keybindings) ? [...settings.keybindings] : [];
    let changed = false;
    for (const tweak of requestedTweaks) {
        const keys = windowsTerminalKeysForTweak(tweak);
        const input = windowsTerminalInputForTweak(tweak);
        const actionId = windowsTerminalActionIdForTweak(tweak);
        const action = createWindowsTerminalAction(tweak);
        const actionIndex = actions.findIndex((candidate) => candidate.id === actionId);
        if (actionIndex >= 0) {
            const existing = actions[actionIndex];
            if (getWindowsTerminalActionInput(existing) !== input) {
                actions[actionIndex] = action;
                changed = true;
            }
        }
        else {
            actions.push(action);
            changed = true;
        }
        const conflictingBindingIndexes = keybindings
            .map((candidate, index) => ({ candidate, index }))
            .filter(({ candidate }) => typeof candidate.keys === "string" && candidate.keys.toLowerCase() === keys && candidate.id !== actionId)
            .map(({ index }) => index)
            .reverse();
        for (const index of conflictingBindingIndexes) {
            keybindings.splice(index, 1);
            changed = true;
        }
        const keybinding = createWindowsTerminalKeybinding(tweak);
        const keybindingIndex = keybindings.findIndex((candidate) => candidate.id === actionId);
        if (keybindingIndex >= 0) {
            const existing = keybindings[keybindingIndex];
            if (existing.keys !== keys) {
                keybindings[keybindingIndex] = keybinding;
                changed = true;
            }
        }
        else {
            keybindings.push(keybinding);
            changed = true;
        }
    }
    if (!changed)
        return { path, changed: false, message: "Windows Terminal tweaks are already installed" };
    const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
    const backupPath = `${path}.threadwell-backup-${timestamp}`;
    copyFileSync(path, backupPath);
    const updated = { ...settings, actions, keybindings };
    writeFileSync(path, `${JSON.stringify(updated, null, 2)}\n`, "utf-8");
    return { path, changed: true, backupPath, message: "Updated Windows Terminal tweaks" };
}
export function getTerminalTweaksStatus() {
    const wezTerm = getWezTermTweaksStatus();
    const windowsTerminal = getWindowsTerminalTweaksStatus();
    return {
        path: process.platform === "win32" && windowsTerminal.path ? windowsTerminal.path : wezTerm.path,
        installed: [...wezTerm.installed, ...windowsTerminal.installed],
        hasThreadwellBlock: wezTerm.hasThreadwellBlock || windowsTerminal.hasThreadwellBlock,
    };
}
export function applyTerminalTweaks(requestedTweaks) {
    const wezTermTweaks = requestedTweaks.filter((tweak) => tweak.startsWith("wezterm-"));
    const windowsTerminalTweaks = requestedTweaks.filter((tweak) => tweak.startsWith("windows-terminal-"));
    const results = [];
    if (wezTermTweaks.length > 0)
        results.push(applyWezTermTweaks(wezTermTweaks));
    if (windowsTerminalTweaks.length > 0)
        results.push(applyWindowsTerminalTweaks(windowsTerminalTweaks));
    if (results.length === 0)
        return { path: "", changed: false, message: "No terminal tweaks selected" };
    if (results.length === 1)
        return results[0];
    return {
        path: results.map((result) => result.path).join(", "),
        changed: results.some((result) => result.changed),
        backupPath: results
            .map((result) => result.backupPath)
            .filter((backupPath) => backupPath !== undefined)
            .join(", "),
        message: results.map((result) => result.message).join("; "),
    };
}
//# sourceMappingURL=terminal-tweaks.js.map