/**
 * Judgment log — records agent decision-making during autonomous mode.
 *
 * When the agent makes a non-trivial call between alternatives, it logs a
 * JudgmentEntry. These accumulate in .sf/runtime/judgment-log.jsonl and are
 * surfaced at milestone close (low-confidence entries bubble into the summary).
 *
 * Storage: sfRuntimeRoot(basePath)/judgment-log.jsonl — runtime artifact.
 *
 * The tool `sf_log_judgment` (registered in dynamic-tools.ts or equivalent)
 * calls appendJudgment(). readJudgmentLog() is used by the compounding step.
 */

import {
	appendFileSync,
	existsSync,
	mkdirSync,
	readFileSync,
} from "node:fs";
import { join } from "node:path";

import { sfRuntimeRoot } from "./paths.js";

export interface JudgmentEntry {
	/** ISO 8601 timestamp */
	ts: string;
	/** Unit ID the decision was made in, e.g. "M001/S01/T01" */
	unitId: string;
	/** Short description of the decision taken */
	decision: string;
	/** Alternatives that were considered but not chosen */
	alternatives: string[];
	/** Reasoning for the chosen decision */
	reasoning: string;
	/** Agent-assessed confidence in the decision */
	confidence: "low" | "medium" | "high";
}

/**
 * Append a single judgment entry to the judgment log JSONL file.
 * Creates the file and parent directories on first call.
 * Failure is non-fatal — silently swallowed so the agent loop is not disrupted.
 */
export function appendJudgment(
	basePath: string,
	entry: Omit<JudgmentEntry, "ts">,
): void {
	try {
		const logPath = resolveJudgmentLogPath(basePath);
		mkdirSync(join(logPath, ".."), { recursive: true });
		const full: JudgmentEntry = { ts: new Date().toISOString(), ...entry };
		appendFileSync(logPath, JSON.stringify(full) + "\n", "utf-8");
	} catch {
		// Non-fatal — judgment logging must never break the agent loop
	}
}

/**
 * Read judgment log entries, optionally filtered by unitId prefix.
 *
 * @param basePath - project root
 * @param unitId - optional filter; when provided, only entries whose unitId
 *   starts with this value are returned (e.g. "M001" returns all M001 entries)
 */
export function readJudgmentLog(
	basePath: string,
	unitId?: string,
): JudgmentEntry[] {
	const logPath = resolveJudgmentLogPath(basePath);
	if (!existsSync(logPath)) return [];

	try {
		const raw = readFileSync(logPath, "utf-8");
		const entries: JudgmentEntry[] = [];
		for (const line of raw.split("\n")) {
			const trimmed = line.trim();
			if (!trimmed) continue;
			try {
				const parsed = JSON.parse(trimmed) as JudgmentEntry;
				if (unitId && !parsed.unitId.startsWith(unitId)) continue;
				entries.push(parsed);
			} catch {
				// Skip malformed lines
			}
		}
		return entries;
	} catch {
		return [];
	}
}

/**
 * Resolve the absolute path to the judgment log file.
 */
export function resolveJudgmentLogPath(basePath: string): string {
	return join(sfRuntimeRoot(basePath), "judgment-log.jsonl");
}
