import * as fs from 'fs';
import * as path from 'path';
import { buildRoutineListJson } from '../scheduling/routines.js';
import { backfillActiveRowsFromIndex, isRunningLiveSession, serializeActiveSessionsForJson, serializeSessionsJson } from '../session/active.js';
import { getConfigValue, loadAutoLaunchPreferences } from '../device-config.js';
import { loadDevices } from '../devices/registry.js';
import { machineId } from '../machine-id.js';
import { querySessions } from '../session/db.js';
import { readActiveSessionsCache } from '../session/session-cache.js';
import { getRuntimeStateDir } from '../state.js';
import { getCliVersion } from '../version.js';
/**
 * The full registered-device roster for the menu bar, from the local registry
 * file only (no ssh, no stats probe) — as cheap as `buildRoutineListJson()`, so
 * it rides the same 3-minute snapshot poll instead of a second timer.
 */
async function buildMenubarDevices() {
    const reg = await loadDevices();
    // Pass the roster so a fleet-wide default (fleet.defaults.config) reaches
    // devices that have no doc of their own.
    const prefs = loadAutoLaunchPreferences(Object.keys(reg));
    const interactiveHost = getConfigValue('interactive.host').value;
    const self = machineId();
    return Object.keys(reg)
        .sort()
        .map((name) => ({
        name,
        platform: reg[name].platform,
        interactive: name === interactiveHost,
        isLocal: name === self,
        preferred: prefs[name]?.preferred === true,
    }));
}
export function readLastWatchdogTick(stateDir = path.join(getRuntimeStateDir(), 'watchdog')) {
    try {
        return JSON.parse(fs.readFileSync(path.join(stateDir, 'last-tick.json'), 'utf-8'));
    }
    catch {
        return null;
    }
}
/** One-process read model for AGI Menu's repeating three-minute refresh. */
export async function computeMenubarSnapshot() {
    const [routines, recent, devices] = await Promise.all([
        Promise.resolve(buildRoutineListJson()),
        Promise.resolve(querySessions({ limit: 40, skipExistenceCheck: true })),
        buildMenubarDevices(),
    ]);
    const active = readActiveSessionsCache('local');
    const rawSessions = active?.sessions ?? [];
    // The raw cache is never filtered at write time (RUSH-2336) — it retains
    // queued/closed/crashed rows so `--queued`/`--closed`/`--crashed` can
    // recover them, and the daemon's warm-tick gather (unlike the CLI's own
    // local gather) never stamps `machine` on a row. Stamp self here — this IS
    // the 'local' scope by construction — then apply the ONE canonical
    // bare-active selector so the menubar never shows a retained dead/queued
    // row nor a process row of unverified liveness.
    const self = machineId();
    for (const s of rawSessions)
        if (!s.machine)
            s.machine = self;
    const activeSessions = rawSessions.filter(isRunningLiveSession);
    backfillActiveRowsFromIndex(activeSessions);
    return {
        version: 1,
        capturedAt: new Date().toISOString(),
        cliVersion: getCliVersion(),
        routines,
        recentSessions: JSON.parse(serializeSessionsJson(recent)),
        activeSessions: serializeActiveSessionsForJson(activeSessions),
        devices,
        watchdog: {
            enabled: getConfigValue('watchdog.enabled').value === true,
            lastTick: (() => {
                const tick = readLastWatchdogTick();
                return tick ? { didNudge: tick.didNudge, counts: tick.counts } : null;
            })(),
        },
    };
}
