import { SettingsManager } from "../../sdk/coding-agent/index.js";
import { getMemoryState, rawTokensSinceLastBound, rawTokensSinceLastCompaction, } from "../branch.js";
import { observationPoolTokens as estimateObservationPoolTokens } from "../compaction.js";
import { countByRelevance, formatRelevanceHistogram } from "../relevance.js";
import { estimateStringTokens } from "../tokens.js";
import { reflectionContent } from "../types.js";
export function registerStatusCommand(ext, runtime) {
    ext.registerCommand("om-status", {
        description: "Show observational memory status",
        handler: async (_args, ctx) => {
            runtime.ensureConfig(ctx.cwd);
            const entries = ctx.sessionManager.getBranch();
            const sinceBound = rawTokensSinceLastBound(entries);
            const sinceCompaction = rawTokensSinceLastCompaction(entries);
            const { reflections: committedRefs, committedObs, pendingObs } = getMemoryState(entries);
            const committedRefItems = committedRefs;
            const committedObsTokens = estimateObservationPoolTokens(committedObs);
            const committedObsCount = committedObs.length;
            const committedRefsTokens = committedRefItems.reduce((s, r) => s + estimateStringTokens(reflectionContent(r)), 0);
            const committedRefsCount = committedRefItems.length;
            const pendingObsTokens = estimateObservationPoolTokens(pendingObs);
            const pendingObsCount = pendingObs.length;
            const relevanceHistogram = countByRelevance([...committedObs, ...pendingObs]);
            const keepRecentTokens = SettingsManager.create(ctx.cwd).getCompactionKeepRecentTokens();
            const obsThreshold = runtime.config.observationThresholdTokens;
            const compThreshold = runtime.config.compactionThresholdTokens;
            const refThreshold = runtime.config.reflectionThresholdTokens;
            // Approximation: the real compaction gate excludes pending obs whose coversFromId falls inside
            // the new keep-recent tail (deferred to next cycle) and adds any sync-catch-up gap obs produced
            // at compaction entry. We over-count by the tail slice and can't predict the gap obs here.
            // Precise version would simulate the new firstKeptEntryId by walking back keepRecentTokens from
            // the branch tail and split pending into pre-tail vs tail-covering.
            const observationPoolTokens = estimateObservationPoolTokens([...committedObs, ...pendingObs]);
            const obsPct = Math.min(100, Math.round((sinceBound / obsThreshold) * 100));
            const compPct = Math.min(100, Math.round((sinceCompaction / compThreshold) * 100));
            const refPct = Math.min(100, Math.round((observationPoolTokens / refThreshold) * 100));
            const refLabel = committedRefsCount === 1 ? "entry" : "entries";
            const cObsLabel = committedObsCount === 1 ? "observation" : "observations";
            const pObsLabel = pendingObsCount === 1 ? "observation" : "observations";
            const passiveLines = runtime.config.passive === true
                ? [
                    "### Mode",
                    "Passive: proactive observation and compaction triggers disabled; compaction hook remains active",
                    "",
                ]
                : [];
            const activityLines = runtime.config.passive === true
                ? [
                    "### Activity",
                    `Observation trigger: passive (~${sinceBound.toLocaleString()} / ${obsThreshold.toLocaleString()} tokens, ${obsPct}%)`,
                    "  → proactive observation is disabled; manual/Pi compaction can still run sync catch-up observation",
                    `Compaction trigger:  passive (~${sinceCompaction.toLocaleString()} / ${compThreshold.toLocaleString()} tokens, ${compPct}%)`,
                    "  → proactive extension-triggered compaction is disabled; manual/Pi compaction still uses the custom hook",
                    `Next reflection:     ~${observationPoolTokens.toLocaleString()} / ${refThreshold.toLocaleString()} tokens (${refPct}%)`,
                    `  → if observations exceed ${refThreshold.toLocaleString()} tokens when compaction runs, reflections are`,
                    `    distilled from them and redundant observations are pruned away`,
                ]
                : [
                    "### Activity",
                    `Next observation: ~${sinceBound.toLocaleString()} / ${obsThreshold.toLocaleString()} tokens (${obsPct}%)`,
                    `  → at ${obsThreshold.toLocaleString()} tokens, recent conversation is compressed into new observations`,
                    `Next compaction:  ~${sinceCompaction.toLocaleString()} / ${compThreshold.toLocaleString()} tokens (${compPct}%)`,
                    `  → at ${compThreshold.toLocaleString()} tokens, raw history is replaced by the updated reflections and`,
                    `    observations, keeping only the last ${keepRecentTokens.toLocaleString()} tokens of conversation verbatim`,
                    `Next reflection:  ~${observationPoolTokens.toLocaleString()} / ${refThreshold.toLocaleString()} tokens (${refPct}%)`,
                    `  → if observations exceed ${refThreshold.toLocaleString()} tokens when compaction runs, reflections are`,
                    `    distilled from them and redundant observations are pruned away`,
                ];
            const lines = [
                ...passiveLines,
                "### Memory",
                `Reflections:   ~${committedRefsTokens.toLocaleString()} tokens (${committedRefsCount} ${refLabel})      — durable insights`,
                `Observations:`,
                `  committed    ~${committedObsTokens.toLocaleString()} tokens (${committedObsCount} ${cObsLabel}) — folded into last compaction`,
                `  pending      ~${pendingObsTokens.toLocaleString()} tokens (${pendingObsCount} ${pObsLabel}) — waiting for next compaction`,
                `  relevance    ${formatRelevanceHistogram(relevanceHistogram)}`,
                "",
                ...activityLines,
            ];
            if (runtime.observerInFlight || runtime.compactInFlight) {
                lines.push("");
                lines.push("### In Flight");
                if (runtime.observerInFlight)
                    lines.push("Observer: running");
                if (runtime.compactInFlight)
                    lines.push("Compaction: running");
            }
            ctx.ui.notify(lines.join("\n"), "info");
        },
    });
}
