/**
 * olam memory status — diagnostic dump for the agent-memory Docker container.
 *
 * Phase B substrate: queries `MemoryServiceContainerController.status()` +
 * bearer-authenticated livez probe. Output schema preserves the Phase A
 * shape — `state | livez | secret | port` — but the `state` field now
 * reports container lifecycle (`running | stopped | missing`) instead of
 * pid/alive.
 *
 * Enrichment (additive, backward-compatible): a single `docker inspect` call
 * augments the dump with container runtime metadata — `uptime` (from
 * `State.StartedAt`), `restarts` (`RestartCount`, with a crash-loop warning
 * past a threshold), and `health` (Docker `State.Health.Status`, or `none`
 * for images without a HEALTHCHECK). All new fields are display-only and
 * additive in both human + `--json` modes; existing field names/types and the
 * exit-code contract (anchored on `state` + `livez`) are unchanged.
 *
 * Plan reference: docs/plans/memory-service-as-docker-peripheral/phase-b-tasks.md B3
 */
import { existsSync } from 'node:fs';
import { printInfo, printHeader, printWarning, formatAge } from '../../output.js';
import { hasMemorySecret, readMemorySecretOrNull } from '../../lib/memory-secret.js';
import { MEMORY_LIVEZ_URL, MEMORY_REST_PORT, MEMORY_PID_PATH, } from './_paths.js';
import { MemoryServiceContainerController, } from '../memory-service-container.js';
/**
 * Restart count at/above which `olam memory status` surfaces a crash-loop
 * warning. A couple of restarts across a host reboot or a deliberate
 * `docker restart` are benign; a climbing count under `unless-stopped` is the
 * signal we want operators to notice.
 */
const RESTART_CHURN_THRESHOLD = 3;
async function probe(secret) {
    try {
        const headers = {};
        if (secret)
            headers.authorization = `Bearer ${secret}`;
        const resp = await fetch(MEMORY_LIVEZ_URL, { headers });
        if (resp.status === 401)
            return 'unauthorized';
        if (!resp.ok)
            return 'unknown';
        const body = (await resp.json());
        return body.status === 'ok' ? 'ok' : 'unknown';
    }
    catch {
        return 'unreachable';
    }
}
export async function collectMemoryStatus() {
    const controller = new MemoryServiceContainerController();
    const containerStatus = controller.status();
    const secret = readMemorySecretOrNull();
    const livez = await probe(secret);
    // Best-effort runtime metadata — `null` when the container is missing or a
    // `docker inspect` field fails to parse. Display-only; never gates exit code.
    const runtime = containerStatus.state === 'missing' ? null : controller.runtimeInspect();
    return {
        state: containerStatus.state,
        containerId: containerStatus.containerId ?? null,
        livez,
        secretSet: hasMemorySecret(),
        port: MEMORY_REST_PORT,
        legacyPidfilePresent: existsSync(MEMORY_PID_PATH),
        startedAt: runtime?.startedAt ?? null,
        restartCount: runtime?.restartCount ?? null,
        health: runtime?.health ?? 'unknown',
    };
}
export async function runMemoryStatus(opts = {}) {
    const s = await collectMemoryStatus();
    if (opts.json) {
        process.stdout.write(JSON.stringify(s, null, 2) + '\n');
        return s.livez === 'ok' ? 0 : 1;
    }
    printHeader('olam memory status');
    printInfo('state', s.state);
    if (s.containerId)
        printInfo('container', s.containerId.slice(0, 12));
    if (s.startedAt)
        printInfo('uptime', formatAge(s.startedAt));
    if (s.restartCount !== null)
        printInfo('restarts', String(s.restartCount));
    if (s.health !== 'unknown')
        printInfo('health', s.health);
    printInfo('livez', s.livez);
    printInfo('secret', s.secretSet ? '~/.olam/memory-secret (set)' : '(missing)');
    printInfo('port', `${s.port}`);
    if (s.legacyPidfilePresent) {
        printWarning('~/.olam/memory.pid is present (Phase A legacy artefact). ' +
            'Will be cleaned up on next `olam memory start` or `olam memory stop`.');
    }
    // Crash-loop signal: a high restart count means the container has been
    // bouncing even if it's healthy right now. Non-gating (display + warn only).
    if (s.restartCount !== null && s.restartCount >= RESTART_CHURN_THRESHOLD) {
        printWarning(`container has restarted ${s.restartCount} times (restart policy: unless-stopped). ` +
            'A persistently climbing count points at a crash loop — check `olam memory logs` for repeated startup failures.');
    }
    if (s.health === 'unhealthy') {
        printWarning("Docker reports the container as 'unhealthy'. Check `olam memory logs` for the failing healthcheck.");
    }
    if (s.state === 'running' && s.livez === 'ok')
        return 0;
    if (s.state === 'missing') {
        printWarning('no olam-memory-service container exists; run `olam memory start`');
        return 1;
    }
    if (s.livez === 'unauthorized') {
        printWarning('livez returned 401 — the container is up but the local secret does not match. ' +
            'The container was likely started with a different secret. ' +
            '`olam memory stop && olam memory start` will reconcile.');
        return 1;
    }
    if (s.livez === 'unreachable' && s.state === 'running') {
        printWarning('container is running but /agentmemory/livez did not respond. ' +
            'Check `olam memory logs` for startup errors.');
        return 1;
    }
    if (!s.secretSet) {
        printWarning('secret missing; `olam memory start` will generate it');
    }
    return s.livez === 'ok' ? 0 : 1;
}
export function registerMemoryStatus(cmd) {
    cmd
        .command('status')
        .description('Diagnostic dump for the agent-memory Docker container (Phase B substrate).')
        .option('--json', 'Machine-readable JSON output', false)
        .action(async (opts) => {
        const rc = await runMemoryStatus(opts);
        if (rc !== 0)
            process.exitCode = rc;
    });
}
//# sourceMappingURL=status.js.map