/**
 * Tests for Mechanism 3 — judgment log.
 *
 * Covers:
 *   - appendJudgment creates the JSONL file with correct fields
 *   - readJudgmentLog returns empty array when file doesn't exist
 *   - readJudgmentLog returns all entries when no unitId filter
 *   - readJudgmentLog filters by unitId prefix
 *   - appendJudgment is non-fatal on bad path (does not throw)
 *   - ts field is a valid ISO 8601 timestamp
 */

import assert from "node:assert/strict";
import {
	mkdirSync,
	mkdtempSync,
	readFileSync,
	rmSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { test } from 'vitest';

import { appendJudgment, readJudgmentLog, resolveJudgmentLogPath } from "../judgment-log.ts";

function makeTmpProject(): string {
	const dir = mkdtempSync(join(tmpdir(), "sf-judgment-"));
	mkdirSync(join(dir, ".sf"), { recursive: true });
	return dir;
}

test("judgment-log: appendJudgment creates JSONL file", () => {
	const dir = makeTmpProject();
	try {
		appendJudgment(dir, {
			unitId: "M001/S01/T01",
			decision: "Used uv run for verification",
			alternatives: ["python -m pytest directly", "skip verification"],
			reasoning: "Project has uv.lock; uv-managed env is canonical",
			confidence: "high",
		});
		const logPath = resolveJudgmentLogPath(dir);
		const content = readFileSync(logPath, "utf-8");
		const parsed = JSON.parse(content.trim().split("\n")[0]);
		assert.strictEqual(parsed.unitId, "M001/S01/T01");
		assert.strictEqual(parsed.decision, "Used uv run for verification");
		assert.strictEqual(parsed.confidence, "high");
		assert.ok(Array.isArray(parsed.alternatives));
		assert.ok(parsed.ts, "should have ts field");
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("judgment-log: ts field is a valid ISO 8601 timestamp", () => {
	const dir = makeTmpProject();
	try {
		appendJudgment(dir, {
			unitId: "M001/S01/T01",
			decision: "choice",
			alternatives: [],
			reasoning: "reason",
			confidence: "medium",
		});
		const entries = readJudgmentLog(dir);
		assert.ok(entries.length > 0);
		const ts = entries[0].ts;
		const d = new Date(ts);
		assert.ok(!Number.isNaN(d.getTime()), `ts should be valid date, got: ${ts}`);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("judgment-log: readJudgmentLog returns empty array when file does not exist", () => {
	const dir = makeTmpProject();
	try {
		const entries = readJudgmentLog(dir);
		assert.deepEqual(entries, []);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("judgment-log: readJudgmentLog returns all entries without filter", () => {
	const dir = makeTmpProject();
	try {
		appendJudgment(dir, {
			unitId: "M001/S01/T01",
			decision: "d1",
			alternatives: [],
			reasoning: "r1",
			confidence: "low",
		});
		appendJudgment(dir, {
			unitId: "M002/S01/T01",
			decision: "d2",
			alternatives: [],
			reasoning: "r2",
			confidence: "high",
		});
		const entries = readJudgmentLog(dir);
		assert.strictEqual(entries.length, 2);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("judgment-log: readJudgmentLog filters by unitId prefix", () => {
	const dir = makeTmpProject();
	try {
		appendJudgment(dir, {
			unitId: "M001/S01/T01",
			decision: "d1",
			alternatives: [],
			reasoning: "r1",
			confidence: "low",
		});
		appendJudgment(dir, {
			unitId: "M002/S01/T01",
			decision: "d2",
			alternatives: [],
			reasoning: "r2",
			confidence: "high",
		});
		const entries = readJudgmentLog(dir, "M001");
		assert.strictEqual(entries.length, 1);
		assert.strictEqual(entries[0].unitId, "M001/S01/T01");
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("judgment-log: appendJudgment is non-fatal when base directory does not exist", () => {
	// Provide a non-existent directory — should not throw
	assert.doesNotThrow(() => {
		appendJudgment("/tmp/nonexistent-sf-test-dir-12345/project", {
			unitId: "M001/S01/T01",
			decision: "test",
			alternatives: [],
			reasoning: "test",
			confidence: "low",
		});
	});
});
