//! Terminal capability probing for inline kitty graphics in the plain
//! CLI commands (the TUI gets this from vaxis).
//!
//! v1 uses environment heuristics plus a TTY check; it does not actively
//! query the terminal. The cell pixel size defaults to a common 8x16 -
//! kitty scales the transmitted image to the requested cell footprint,
//! so the default only affects render crispness, not layout. (An active
//! `CSI 16 t` cell-size query is a sensible follow-up.)

const std = @import("std");
const term_graphics = @import("term_graphics.zig");

pub const Caps = struct {
    /// The terminal appears to speak the kitty graphics protocol.
    kitty: bool = false,
    /// Cell pixel size used to size inline charts.
    cell_w: u32 = term_graphics.default_cell_w,
    cell_h: u32 = term_graphics.default_cell_h,
};

/// Detect inline-graphics capability. Graphics escapes are only ever
/// emitted to a real terminal, never into a pipe or file, so a non-TTY
/// stdout always yields `.kitty = false` (callers fall back to braille).
pub fn detect(io: std.Io, environ_map: *const std.process.Environ.Map) Caps {
    const is_tty = std.Io.File.stdout().isTty(io) catch false;
    if (!is_tty) return .{};
    return .{ .kitty = kittyFromEnv(environ_map) };
}

/// Environment heuristic for kitty-graphics support. Recognizes kitty,
/// Ghostty, and WezTerm - the common terminals implementing the
/// protocol. (iTerm2 uses a different image protocol and is not matched.)
pub fn kittyFromEnv(env: *const std.process.Environ.Map) bool {
    if (env.get("TERM")) |t| {
        if (std.mem.indexOf(u8, t, "kitty") != null) return true;
    }
    if (env.get("KITTY_WINDOW_ID") != null) return true;
    if (env.get("GHOSTTY_RESOURCES_DIR") != null) return true;
    if (env.get("GHOSTTY_BIN_DIR") != null) return true;
    if (env.get("WEZTERM_EXECUTABLE") != null) return true;
    if (env.get("WEZTERM_PANE") != null) return true;
    if (env.get("TERM_PROGRAM")) |p| {
        if (std.mem.eql(u8, p, "ghostty")) return true;
        if (std.mem.eql(u8, p, "WezTerm")) return true;
    }
    return false;
}

// ── Tests ─────────────────────────────────────────────────────────────

const testing = std.testing;

test "kittyFromEnv: kitty TERM" {
    var env = std.process.Environ.Map.init(testing.allocator);
    defer env.deinit();
    try env.put("TERM", "xterm-kitty");
    try testing.expect(kittyFromEnv(&env));
}

test "kittyFromEnv: KITTY_WINDOW_ID, ghostty, wezterm" {
    {
        var env = std.process.Environ.Map.init(testing.allocator);
        defer env.deinit();
        try env.put("TERM", "xterm-256color");
        try env.put("KITTY_WINDOW_ID", "1");
        try testing.expect(kittyFromEnv(&env));
    }
    {
        var env = std.process.Environ.Map.init(testing.allocator);
        defer env.deinit();
        try env.put("TERM_PROGRAM", "ghostty");
        try testing.expect(kittyFromEnv(&env));
    }
    {
        var env = std.process.Environ.Map.init(testing.allocator);
        defer env.deinit();
        try env.put("WEZTERM_PANE", "0");
        try testing.expect(kittyFromEnv(&env));
    }
}

test "kittyFromEnv: plain xterm / Apple Terminal is not kitty" {
    var env = std.process.Environ.Map.init(testing.allocator);
    defer env.deinit();
    try env.put("TERM", "xterm-256color");
    try env.put("TERM_PROGRAM", "Apple_Terminal");
    try testing.expect(!kittyFromEnv(&env));
}

test "Caps defaults to the assumed cell size, no kitty" {
    const c: Caps = .{};
    try testing.expect(!c.kitty);
    try testing.expectEqual(term_graphics.default_cell_w, c.cell_w);
    try testing.expectEqual(term_graphics.default_cell_h, c.cell_h);
}
