import { BACKENDS, detectCurrentBackend } from './backends/index.js';
/**
 * `ActiveSession.host` -> the backend that can open a new surface in it.
 *
 * Deliberately partial. A host is listed ONLY when the engine can really drive
 * it, because a wrong mapping opens the wrong app and looks like success:
 *   - `code` / `cursor` / `windsurf` are absent even though the engine has an
 *     editor backend — the registered `vscodium-agent` is bound to the VSCodium
 *     variant (backends/vscodium-agent.ts: `EDITOR_VARIANTS[0]`), so mapping
 *     Cursor to it would open VSCodium instead of Cursor.
 *   - `warp` / `kitty` / `wezterm` / `alacritty` / `hyper` / `screen` are absent
 *     because no backend drives them yet.
 * An unmapped host isn't an error — resolution simply moves to the next session,
 * and ultimately to the available-backend floor.
 */
export const SESSION_HOST_BACKENDS = Object.freeze({
    iterm: 'iterm',
    ghostty: 'ghostty',
    terminal: 'terminal',
    tmux: 'tmux',
    codium: 'vscodium-agent',
});
/** Most recent first. Falls back to start time, then to the given order. */
function byRecency(a, b) {
    const at = a.lastActivityMs ?? a.startedAtMs ?? 0;
    const bt = b.lastActivityMs ?? b.startedAtMs ?? 0;
    return bt - at;
}
const realIsAvailable = (backend, ctx) => BACKENDS[backend].isAvailable(ctx);
/**
 * The backend for the terminal the user's most recent live session runs in, or
 * null when no live session names a host this engine can drive. Pure — the
 * caller supplies the sessions, so the precedence is unit-testable without a
 * process table.
 */
export function backendFromSessions(sessions, ctx, deps = {}) {
    const isAvailable = deps.isAvailable ?? realIsAvailable;
    for (const s of [...sessions].sort(byRecency)) {
        // The app an attached tmux client is in beats the multiplexer name.
        const host = s.viewingApp ?? s.host;
        if (!host)
            continue;
        // hasOwn, not a bare index: the host is data, and `SESSION_HOST_BACKENDS['constructor']`
        // would otherwise hand back a prototype member that BACKENDS cannot key on.
        if (!Object.hasOwn(SESSION_HOST_BACKENDS, host))
            continue;
        const backend = SESSION_HOST_BACKENDS[host];
        if (!backend)
            continue;
        if (!isAvailable(backend, ctx))
            continue;
        return { backend, host };
    }
    return null;
}
/**
 * Resolve the terminal to open a new surface in. Pure. Returns null when this
 * machine has no drivable terminal at all (Linux with no tmux, an SSH session),
 * which callers must handle — never a guess that silently goes nowhere.
 */
export function resolveLaunchBackend(ctx, sessions = [], deps = {}) {
    const isAvailable = deps.isAvailable ?? realIsAvailable;
    const current = detectCurrentBackend(ctx);
    if (current && isAvailable(current, ctx)) {
        return { backend: current, source: 'current-terminal' };
    }
    const fromSession = backendFromSessions(sessions, ctx, deps);
    if (fromSession) {
        return { backend: fromSession.backend, source: 'active-session', host: fromSession.host };
    }
    const first = Object.keys(BACKENDS).find((b) => isAvailable(b, ctx));
    return first ? { backend: first, source: 'available' } : null;
}
/** One line explaining a choice, for the `agents run --terminal` preamble. */
export function describeBackendChoice(choice) {
    const label = BACKENDS[choice.backend].label;
    switch (choice.source) {
        case 'forced':
            return `${label} (you asked for it)`;
        case 'current-terminal':
            return `${label} (the terminal you're in)`;
        case 'active-session':
            return `${label} (where your ${choice.host} sessions run)`;
        case 'available':
            return `${label} (no running session named a terminal)`;
    }
}
