/**
 * `shieldcortex inspect <subcommand>` (v4.25.0)
 *
 * Operator surface for the precompact ring buffer. Reads what the precompact
 * hook proposed during its last run(s), which proposals landed, and which
 * were dropped — useful when tuning thresholds or chasing weird auto-extract
 * behaviour.
 *
 * Subcommands:
 *   shieldcortex inspect last-precompact [--history N | --all]
 */
// ANSI colours — match doctor.ts conventions.
const bold = '\x1b[1m';
const reset = '\x1b[0m';
const green = '\x1b[32m';
const yellow = '\x1b[33m';
const red = '\x1b[31m';
const cyan = '\x1b[36m';
const dim = '\x1b[2m';
function parseFlag(args, name) {
    const idx = args.indexOf(name);
    if (idx === -1 || idx === args.length - 1)
        return undefined;
    return args[idx + 1];
}
function relativeTime(iso) {
    if (!iso)
        return '';
    const then = Date.parse(iso);
    if (!Number.isFinite(then))
        return '';
    const deltaMs = Date.now() - then;
    const mins = Math.round(deltaMs / 60_000);
    if (mins < 1)
        return '(just now)';
    if (mins < 60)
        return `(${mins} min ago)`;
    const hours = Math.round(mins / 60);
    if (hours < 24)
        return `(${hours}h ago)`;
    const days = Math.round(hours / 24);
    return `(${days}d ago)`;
}
function printEntry(index, entry) {
    const candidates = entry.candidates ?? [];
    const saved = candidates.filter((c) => c.saved);
    const dropped = candidates.filter((c) => !c.saved);
    console.log(`${bold}Slot ${index}: ${entry.ranAt ?? '(unknown time)'} ${dim}${relativeTime(entry.ranAt)}${reset}`);
    const thrLine = entry.thresholdUsed != null ? `threshold ${entry.thresholdUsed.toFixed(2)}` : 'threshold —';
    const fullLine = entry.contextFullnessPct != null
        ? `context ${entry.contextFullnessPct}% full`
        : 'context —';
    const memLine = entry.totalMemories != null ? `${entry.totalMemories} memories` : '';
    console.log(`  ${dim}${thrLine}, ${fullLine}${memLine ? ', ' + memLine : ''}${reset}`);
    console.log(`  Candidates: ${candidates.length} extracted${entry.rawSegmentCount != null ? ` (${entry.rawSegmentCount} raw segments)` : ''}, ${green}${saved.length} saved${reset}, ${dim}${dropped.length} dropped${reset}`);
    if (saved.length > 0) {
        console.log(`\n  ${green}SAVED${reset}`);
        for (const c of saved) {
            const sal = c.salience != null ? c.salience.toFixed(2) : '----';
            const boost = c.frequencyBoost && c.frequencyBoost > 0 ? ` ${dim}+${c.frequencyBoost.toFixed(2)}${reset}` : '';
            console.log(`    ${cyan}${(c.extractorType ?? '?').padEnd(15)}${reset} ${sal}${boost}  ${(c.title ?? '').slice(0, 70)}`);
            console.log(`    ${dim}  → category=${c.category ?? '?'}, purpose=${c.memoryPurpose ?? 'project'}${reset}`);
        }
    }
    if (dropped.length > 0) {
        console.log(`\n  ${red}DROPPED${reset}`);
        for (const c of dropped) {
            const sal = c.salience != null ? c.salience.toFixed(2) : '----';
            const err = c.error ? ` ${yellow}— ${c.error}${reset}` : '';
            console.log(`    ${dim}${(c.extractorType ?? '?').padEnd(15)} ${sal}${reset}  ${(c.title ?? '').slice(0, 70)}${err}`);
        }
    }
    console.log('');
}
async function cmdLastPrecompact(args) {
    const all = args.includes('--all');
    const historyArg = parseFlag(args, '--history');
    const historyIndex = historyArg !== undefined ? parseInt(historyArg, 10) : 0;
    const { readPrecompactLog, listPrecompactLogs, PRECOMPACT_RING_SIZE } = 
    // @ts-expect-error — importing a .mjs hook util that has no .d.ts
    await import('../../scripts/lib/precompact-log.mjs');
    if (all) {
        const entries = listPrecompactLogs();
        if (entries.length === 0) {
            console.log(`${dim}No precompact runs logged yet. Trigger one via a /compact in Claude Code or wait for auto-compact.${reset}`);
            return 0;
        }
        console.log(`${bold}${entries.length} precompact run(s) in ring buffer${reset}\n`);
        for (const { index, entry } of entries)
            printEntry(index, entry);
        return 0;
    }
    if (!Number.isFinite(historyIndex) || historyIndex < 0 || historyIndex >= PRECOMPACT_RING_SIZE) {
        console.error(`--history must be 0..${PRECOMPACT_RING_SIZE - 1}. Got: ${historyArg ?? '<missing>'}`);
        return 2;
    }
    const entry = readPrecompactLog(historyIndex);
    if (!entry) {
        if (historyIndex === 0) {
            console.log(`${dim}No precompact runs logged yet. Trigger one via a /compact in Claude Code or wait for auto-compact.${reset}`);
        }
        else {
            console.log(`${dim}No precompact run at history slot ${historyIndex}.${reset}`);
        }
        return 0;
    }
    printEntry(historyIndex, entry);
    return 0;
}
function fmtRank(rank) {
    if (typeof rank !== 'number' || !Number.isFinite(rank))
        return '   ----';
    return rank.toFixed(2).padStart(7);
}
function fmtEff(eff) {
    if (typeof eff !== 'number' || !Number.isFinite(eff))
        return '----';
    return eff.toFixed(2);
}
function printRecallEntry(index, entry) {
    const candidates = entry.candidates ?? [];
    const injected = candidates.filter((c) => c.injected);
    const dropped = candidates.filter((c) => !c.injected);
    console.log(`${bold}Slot ${index}: ${entry.ranAt ?? '(unknown time)'} ${dim}${relativeTime(entry.ranAt)}${reset}`);
    const promptDisplay = entry.prompt ? `"${entry.prompt}"` : '(no prompt)';
    console.log(`  Prompt: ${cyan}${promptDisplay}${reset}`);
    const meta = [
        entry.project ? `project=${entry.project}` : null,
        entry.sessionId ? `session=${entry.sessionId.slice(0, 8)}` : null,
        entry.minSalience != null ? `min_sal=${entry.minSalience.toFixed(2)}` : null,
    ].filter(Boolean).join(', ');
    if (meta)
        console.log(`  ${dim}${meta}${reset}`);
    console.log(`  Candidates: ${candidates.length} considered, ${green}${injected.length} injected${reset}, ${dim}${dropped.length} dropped${reset}`);
    if (injected.length > 0) {
        console.log(`\n  ${green}INJECTED${reset}`);
        for (const c of injected) {
            const src = (c.source ?? '?').padEnd(15);
            console.log(`    [#${String(c.id ?? '?').padEnd(5)}] ${cyan}${src}${reset} rank=${fmtRank(c.ftsRank)}  eff=${fmtEff(c.effectiveSalience)}  ${(c.title ?? '').slice(0, 70)}`);
        }
    }
    if (dropped.length > 0) {
        console.log(`\n  ${red}DROPPED${reset}`);
        for (const c of dropped) {
            const src = (c.source ?? '?').padEnd(15);
            const reason = c.dropReason ? ` ${yellow}(${c.dropReason})${reset}` : '';
            console.log(`    ${dim}[#${String(c.id ?? '?').padEnd(5)}]${reset} ${dim}${src}${reset} rank=${fmtRank(c.ftsRank)}  eff=${fmtEff(c.effectiveSalience)}  ${dim}${(c.title ?? '').slice(0, 70)}${reset}${reason}`);
        }
    }
    console.log('');
}
async function cmdLastRecall(args) {
    const all = args.includes('--all');
    const historyArg = parseFlag(args, '--history');
    const historyIndex = historyArg !== undefined ? parseInt(historyArg, 10) : 0;
    const { readRecallLog, listRecallLogs, RECALL_RING_SIZE } = 
    // @ts-expect-error — importing a .mjs hook util that has no .d.ts
    await import('../../scripts/lib/recall-log.mjs');
    if (all) {
        const entries = listRecallLogs();
        if (entries.length === 0) {
            console.log(`${dim}No recall runs logged yet. The recall ring buffer fills as the UserPromptSubmit hook fires with proactiveRecall=true.${reset}`);
            return 0;
        }
        console.log(`${bold}${entries.length} recall run(s) in ring buffer${reset}\n`);
        for (const { index, entry } of entries)
            printRecallEntry(index, entry);
        return 0;
    }
    if (!Number.isFinite(historyIndex) || historyIndex < 0 || historyIndex >= RECALL_RING_SIZE) {
        console.error(`--history must be 0..${RECALL_RING_SIZE - 1}. Got: ${historyArg ?? '<missing>'}`);
        return 2;
    }
    const entry = readRecallLog(historyIndex);
    if (!entry) {
        if (historyIndex === 0) {
            console.log(`${dim}No recall runs logged yet. The recall ring buffer fills as the UserPromptSubmit hook fires with proactiveRecall=true.${reset}`);
        }
        else {
            console.log(`${dim}No recall run at history slot ${historyIndex}.${reset}`);
        }
        return 0;
    }
    printRecallEntry(historyIndex, entry);
    return 0;
}
function printHelp() {
    console.log('Usage: shieldcortex inspect <subcommand>');
    console.log('');
    console.log('Subcommands:');
    console.log('  last-precompact [--history N | --all]    Show extractor candidates from the last precompact run');
    console.log('                                           --history N (0=newest, up to 9) — show slot N');
    console.log('                                           --all — show every entry in the ring buffer (newest first)');
    console.log('');
    console.log('  last-recall [--history N | --all]        Show recall candidates from the last prompt-recall run');
    console.log('                                           (requires proactiveRecall=true; logs prompt + per-candidate');
    console.log('                                           FTS rank + effective salience + drop reason).');
    console.log('                                           Note: prompts are stored locally at ~/.shieldcortex/recall-log/');
    console.log('                                           — same trust boundary as memories.db.');
}
export async function handleInspectCommand(args) {
    const sub = args[0];
    let code = 0;
    switch (sub) {
        case 'last-precompact':
            code = await cmdLastPrecompact(args.slice(1));
            break;
        case 'last-recall':
            code = await cmdLastRecall(args.slice(1));
            break;
        case undefined:
        case '--help':
        case '-h':
        case 'help':
            printHelp();
            break;
        default:
            console.error(`Unknown subcommand: inspect ${sub}`);
            printHelp();
            code = 2;
    }
    process.exit(code);
}
