/**
 * Nexus Prime -- Proof Store
 *
 * JSON-file-backed persistence for proof envelopes.
 * Each run gets its own file under `<stateRoot>/proofs/<runId>.json`.
 */
import { readFile, writeFile, readdir, mkdir, stat, unlink } from 'node:fs/promises';
import { join } from 'node:path';
/* ------------------------------------------------------------------ */
/*  Helpers                                                            */
/* ------------------------------------------------------------------ */
const PROOFS_DIR = 'proofs';
const DAY_MS = 24 * 60 * 60 * 1000;
function proofsDir(stateRoot) {
    return join(stateRoot, PROOFS_DIR);
}
function runFile(stateRoot, runId) {
    return join(proofsDir(stateRoot), `${runId}.json`);
}
async function ensureDir(dir) {
    await mkdir(dir, { recursive: true });
}
/* ------------------------------------------------------------------ */
/*  Public API                                                         */
/* ------------------------------------------------------------------ */
/**
 * Append a proof envelope to the per-run JSON file.
 * Creates the file (and directory) if it does not exist yet.
 */
export async function storeProof(stateRoot, envelope) {
    const dir = proofsDir(stateRoot);
    await ensureDir(dir);
    const filePath = runFile(stateRoot, envelope.runId);
    let existing = [];
    try {
        const raw = await readFile(filePath, 'utf-8');
        existing = JSON.parse(raw);
    }
    catch {
        // File does not exist yet -- start fresh.
    }
    existing.push(envelope);
    await writeFile(filePath, JSON.stringify(existing, null, 2), 'utf-8');
}
/**
 * Load all proof envelopes for a given run.
 * Returns an empty array when no proofs have been recorded.
 */
export async function loadProofs(stateRoot, runId) {
    const filePath = runFile(stateRoot, runId);
    try {
        const raw = await readFile(filePath, 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return [];
    }
}
/**
 * List all run IDs that have recorded proofs.
 */
export async function listRunIds(stateRoot) {
    const dir = proofsDir(stateRoot);
    try {
        const entries = await readdir(dir);
        return entries
            .filter((e) => e.endsWith('.json'))
            .map((e) => e.replace(/\.json$/, ''));
    }
    catch {
        return [];
    }
}
/**
 * Remove proof files older than `maxAgeDays` or trim runs that exceed
 * `maxPerRun` envelopes (keeping the most recent).
 */
export async function pruneStaleProofs(stateRoot, maxAgeDays = 90, maxPerRun = 30) {
    const dir = proofsDir(stateRoot);
    const now = Date.now();
    const cutoff = now - maxAgeDays * DAY_MS;
    let entries;
    try {
        entries = await readdir(dir);
    }
    catch {
        return; // Nothing to prune.
    }
    for (const entry of entries) {
        if (!entry.endsWith('.json'))
            continue;
        const filePath = join(dir, entry);
        // Age-based pruning: remove files whose mtime is older than cutoff.
        const info = await stat(filePath);
        if (info.mtimeMs < cutoff) {
            await unlink(filePath);
            continue;
        }
        // Per-run cap: keep only the most recent `maxPerRun` envelopes.
        try {
            const raw = await readFile(filePath, 'utf-8');
            const envelopes = JSON.parse(raw);
            if (envelopes.length > maxPerRun) {
                const trimmed = envelopes
                    .sort((a, b) => b.createdAt - a.createdAt)
                    .slice(0, maxPerRun);
                await writeFile(filePath, JSON.stringify(trimmed, null, 2), 'utf-8');
            }
        }
        catch {
            // Malformed file -- remove it.
            await unlink(filePath);
        }
    }
}
