import { execFileSync } from "node:child_process";
import chalk from "chalk";
/**
 * Detect the best theme for the current terminal.
 *
 * Detection chain for base theme (first match wins):
 * 1. FORCE_THEME env var (explicit override with any ThemeName)
 * 2. VSCODE_THEME_KIND env var (VS Code integrated terminal)
 * 3. macOS system dark mode (defaults read -g AppleInterfaceStyle)
 * 4. OSC 11 escape sequence query (most modern terminals)
 * 5. COLORFGBG env var (rxvt, some other terminals)
 * 6. Default to "dark"
 *
 * Auto-selects ANSI fallback variant when truecolor is not supported.
 */
export async function detectTheme() {
    // 0. Explicit override
    const forceTheme = process.env["FORCE_THEME"];
    if (forceTheme && isValidThemeName(forceTheme)) {
        return forceTheme;
    }
    // 1. VS Code sets this reliably
    const vscodeTheme = process.env["VSCODE_THEME_KIND"];
    if (vscodeTheme) {
        return vscodeTheme.includes("light") ? "light" : "dark";
    }
    // 2. macOS system dark mode — fast, no escape-sequence side effects
    if (process.platform === "darwin") {
        try {
            const result = execFileSync("defaults", ["read", "-g", "AppleInterfaceStyle"], {
                encoding: "utf-8",
                timeout: 500,
                stdio: ["pipe", "pipe", "pipe"],
            });
            return result.trim().toLowerCase() === "dark" ? "dark" : "light";
        }
        catch {
            // Command fails when in light mode (key doesn't exist) — that means light
            return "light";
        }
    }
    // 3. OSC 11 — query actual terminal background color
    let base = await queryOSC11();
    // 4. COLORFGBG — "fg;bg" ANSI color indices
    if (base === null) {
        const colorfgbg = process.env["COLORFGBG"];
        if (colorfgbg) {
            const parts = colorfgbg.split(";");
            const bg = parseInt(parts[parts.length - 1], 10);
            if (!isNaN(bg)) {
                base = bg === 7 || (bg >= 9 && bg <= 15) ? "light" : "dark";
            }
        }
    }
    // 5. Default
    if (base === null)
        base = "dark";
    // Auto-select ANSI variant for terminals without truecolor support
    if (chalk.level < 3) {
        return `${base}-ansi`;
    }
    return base;
}
const VALID_THEMES = new Set([
    "dark",
    "light",
    "dark-ansi",
    "light-ansi",
    "dark-daltonized",
    "light-daltonized",
]);
function isValidThemeName(name) {
    return VALID_THEMES.has(name);
}
/**
 * Send OSC 11 query to the terminal and parse the background color response.
 * Returns "dark" | "light" based on luminance, or null if unsupported.
 *
 * Note: does NOT send the ESC[6n cursor position sentinel — that response
 * (ESC[row;colR) can leak into stdin if not drained before Ink takes over,
 * causing "[2;1R" to appear in the chat input. Instead we rely on a simple
 * timeout to detect unsupported terminals.
 */
// ESC character built without a literal escape so ESLint's no-control-regex is satisfied
const ESC = String.fromCharCode(27);
const oscResponsePattern = new RegExp(ESC + "\\]11;rgb:([0-9a-fA-F]+)/([0-9a-fA-F]+)/([0-9a-fA-F]+)");
function queryOSC11() {
    return new Promise((resolve) => {
        // Skip for multiplexers — they don't forward OSC queries
        const term = process.env["TERM"] ?? "";
        if (term.startsWith("screen") || term.startsWith("tmux")) {
            resolve(null);
            return;
        }
        // Need a real TTY
        if (!process.stdin.isTTY || !process.stdout.isTTY) {
            resolve(null);
            return;
        }
        const wasRaw = process.stdin.isRaw;
        let settled = false;
        const cleanup = () => {
            if (settled)
                return;
            settled = true;
            process.stdin.removeListener("data", onData);
            try {
                process.stdin.setRawMode(wasRaw);
            }
            catch {
                // ignore
            }
            if (!wasRaw) {
                try {
                    process.stdin.pause();
                }
                catch {
                    // ignore
                }
            }
        };
        const timeout = setTimeout(() => {
            cleanup();
            resolve(null);
        }, 200);
        const onData = (data) => {
            const str = data.toString();
            // Look for OSC 11 response: ESC]11;rgb:RRRR/GGGG/BBBB followed by BEL or ST
            const match = str.match(oscResponsePattern);
            if (match) {
                clearTimeout(timeout);
                cleanup();
                // Parse RGB values (can be 1, 2, or 4 hex digits per channel)
                const r = normalizeChannel(match[1]);
                const g = normalizeChannel(match[2]);
                const b = normalizeChannel(match[3]);
                // Relative luminance (ITU-R BT.709)
                const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
                resolve(luminance < 0.5 ? "dark" : "light");
            }
        };
        try {
            process.stdin.setRawMode(true);
            process.stdin.resume();
            process.stdin.on("data", onData);
            // Send only the OSC 11 query — no ESC[6n sentinel to avoid
            // cursor position responses leaking into Ink's input
            process.stdout.write("\x1b]11;?\x1b\\");
        }
        catch {
            clearTimeout(timeout);
            cleanup();
            resolve(null);
        }
    });
}
/** Normalize a hex color channel (1-4 hex digits) to 0.0–1.0 range. */
function normalizeChannel(hex) {
    const value = parseInt(hex, 16);
    switch (hex.length) {
        case 1:
            return value / 0xf;
        case 2:
            return value / 0xff;
        case 4:
            return value / 0xffff;
        default:
            return value / (Math.pow(16, hex.length) - 1);
    }
}
//# sourceMappingURL=detect-theme.js.map