"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.HEARTBEAT_STALE_S = exports.HEARTBEAT_FRESH_S = void 0;
exports.buildStatusReport = buildStatusReport;
exports.renderStatusReport = renderStatusReport;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
// ============================================================================
// `openlife status` — consolidated runtime state report.
//
// Aggregates the 6 most operationally useful files under `.openlife/`:
//   - install-manifest.json     → installed profile + providers detected
//   - heartbeat.json            → daemon uptime + last beat timestamp
//   - runtime-health.json       → per-executor failure budget + cooldown
//   - runtime-policy-status.json → per-executor availability decision
//   - agent-queue.json          → queued objectives + last flush
//   - governance-ledger.jsonl   → tail entry hash + chain length
//
// Computes an `overall` rollup:
//   - "healthy"  → daemon beat within HEARTBEAT_FRESH_S AND at least one
//                  executor available AND governance ledger parseable
//   - "degraded" → heartbeat stale (FRESH..STALE) OR some executors down
//   - "down"     → heartbeat older than STALE OR all executors down
//
// Returns JSON. The CLI wrapper handles --watch (re-print every 5s).
// ============================================================================
exports.HEARTBEAT_FRESH_S = 60;
exports.HEARTBEAT_STALE_S = 300;
function readJsonSafe(filePath) {
    try {
        if (!fs.existsSync(filePath))
            return null;
        return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
    }
    catch {
        return null;
    }
}
function readJsonlTailSafe(filePath, maxLines = 1) {
    try {
        if (!fs.existsSync(filePath))
            return { count: 0 };
        const raw = fs.readFileSync(filePath, 'utf-8');
        const lines = raw.split('\n').filter((l) => l.trim().length > 0);
        if (lines.length === 0)
            return { count: 0 };
        const tail = lines.slice(-Math.max(1, maxLines));
        const lastRaw = tail[tail.length - 1];
        try {
            return { count: lines.length, last: JSON.parse(lastRaw) };
        }
        catch {
            return { count: lines.length };
        }
    }
    catch {
        return { count: 0 };
    }
}
function readPackageVersion(packageRoot) {
    const candidate = path.join(packageRoot, 'package.json');
    const pkg = readJsonSafe(candidate);
    return pkg?.version || '0.0.0';
}
function normalizeExecutors(policyStatus, runtimeHealth) {
    const result = {};
    const policy = (policyStatus?.executors ?? {});
    for (const [name, raw] of Object.entries(policy)) {
        const r = raw;
        result[name] = {
            executor: name,
            available: Boolean(r.available),
            reason: typeof r.reason === 'string' ? r.reason : undefined,
            category: typeof r.category === 'string' ? r.category : undefined,
            updatedAt: typeof r.updatedAt === 'string' ? r.updatedAt : undefined,
        };
    }
    if (runtimeHealth) {
        for (const [name, raw] of Object.entries(runtimeHealth)) {
            if (name === 'type' || name === 'status' || name === 'updatedAt')
                continue;
            const r = raw;
            const current = result[name] || { executor: name, available: true };
            if (typeof r.failures === 'number')
                current.failures = r.failures;
            if (typeof r.until === 'string')
                current.cooldownUntil = r.until;
            if (!current.reason && typeof r.reason === 'string')
                current.reason = r.reason;
            result[name] = current;
        }
    }
    return Object.values(result);
}
function deriveOverall(report) {
    const notes = [];
    const age = report.heartbeat.ageSeconds;
    let heartbeatTier = 'fresh';
    if (!report.heartbeat.present || age === null) {
        heartbeatTier = 'dead';
        notes.push('no_heartbeat');
    }
    else if (age > exports.HEARTBEAT_STALE_S) {
        heartbeatTier = 'dead';
        notes.push(`heartbeat_stale_${age}s`);
    }
    else if (age > exports.HEARTBEAT_FRESH_S) {
        heartbeatTier = 'stale';
        notes.push(`heartbeat_warning_${age}s`);
    }
    const executors = report.executors;
    const anyExecutor = executors.length > 0;
    const anyAvailable = executors.some((e) => e.available);
    if (anyExecutor && !anyAvailable) {
        notes.push('all_executors_down');
    }
    if (anyExecutor && !executors.every((e) => e.available)) {
        const down = executors.filter((e) => !e.available).map((e) => e.executor);
        notes.push(`executors_down:${down.join(',')}`);
    }
    if (!report.governance.ledgerPresent) {
        notes.push('no_governance_ledger');
    }
    let overall;
    if (heartbeatTier === 'dead' || (anyExecutor && !anyAvailable)) {
        overall = 'down';
    }
    else if (heartbeatTier === 'stale' || (anyExecutor && !executors.every((e) => e.available))) {
        overall = 'degraded';
    }
    else {
        overall = 'healthy';
    }
    return { overall, notes };
}
function buildStatusReport(root = process.cwd(), packageRoot) {
    const stateDir = process.env.OPENLIFE_STATE_DIR
        ? path.resolve(process.env.OPENLIFE_STATE_DIR)
        : path.join(root, '.openlife');
    const heartbeat = readJsonSafe(path.join(stateDir, 'heartbeat.json'));
    const runtimeHealth = readJsonSafe(path.join(stateDir, 'runtime-health.json'));
    const policyStatus = readJsonSafe(path.join(stateDir, 'runtime-policy-status.json'));
    const queue = readJsonSafe(path.join(stateDir, 'agent-queue.json'));
    const manifest = readJsonSafe(path.join(stateDir, 'install-manifest.json'));
    const ledgerTail = readJsonlTailSafe(path.join(stateDir, 'governance-ledger.jsonl'), 1);
    const lastLedger = ledgerTail.last;
    const ageSeconds = heartbeat?.ts ? Math.floor((Date.now() - heartbeat.ts) / 1000) : null;
    const uptimeSeconds = heartbeat?.startedAt ? Math.floor((Date.now() - heartbeat.startedAt) / 1000) : null;
    const partial = {
        ts: new Date().toISOString(),
        version: readPackageVersion(packageRoot || path.join(__dirname, '..', '..')),
        profile: manifest?.profile ?? null,
        uptimeSeconds,
        heartbeat: {
            present: Boolean(heartbeat),
            pid: heartbeat?.pid,
            host: heartbeat?.host,
            ageSeconds,
            fresh: ageSeconds !== null && ageSeconds <= exports.HEARTBEAT_FRESH_S,
        },
        governance: {
            ledgerPresent: ledgerTail.count > 0,
            entryCount: ledgerTail.count,
            lastEntryHash: lastLedger?.entryHash,
            lastEntryTs: lastLedger?.ts,
        },
        queue: {
            depth: Array.isArray(queue?.queuedObjectives) ? queue.queuedObjectives.length : 0,
            lastFlushedAt: queue?.lastFlushedAt,
        },
        executors: normalizeExecutors(policyStatus, runtimeHealth),
        install: {
            installedAt: manifest?.installedAt,
            providers: manifest?.providers,
            clis: manifest?.clis,
            hasTelegramToken: manifest?.envChecks?.hasTelegramToken,
        },
    };
    const { overall, notes } = deriveOverall(partial);
    return { ...partial, overall, notes };
}
function renderStatusReport(report) {
    return JSON.stringify(report, null, 2);
}
