/**
 * Tests for Mechanism 1 — tacit knowledge files and system-context injection.
 *
 * Covers:
 *   - SCAFFOLD_FILES includes .sf/PRINCIPLES.md, .sf/TASTE.md, .sf/ANTI-GOALS.md
 *   - ensureAgenticDocsScaffold creates the three tacit knowledge files
 *   - loadTacitKnowledgeBlock returns empty string when files are missing
 *   - loadTacitKnowledgeBlock injects present files into the block
 *   - Scaffold markers are stripped from emitted block
 *   - Sections exceeding 4 KB are truncated with a note
 */

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

import { SCAFFOLD_FILES, ensureAgenticDocsScaffold } from "../agentic-docs-scaffold.ts";
import { loadTacitKnowledgeBlock } from "../bootstrap/system-context.ts";

// ─── Scaffold file registration ───────────────────────────────────────────────

test("tacit-knowledge: SCAFFOLD_FILES includes .sf/PRINCIPLES.md", () => {
	const paths = SCAFFOLD_FILES.map((f) => f.path);
	assert.ok(
		paths.includes(".sf/PRINCIPLES.md"),
		"SCAFFOLD_FILES should include .sf/PRINCIPLES.md",
	);
});

test("tacit-knowledge: SCAFFOLD_FILES includes .sf/TASTE.md", () => {
	const paths = SCAFFOLD_FILES.map((f) => f.path);
	assert.ok(paths.includes(".sf/TASTE.md"), "SCAFFOLD_FILES should include .sf/TASTE.md");
});

test("tacit-knowledge: SCAFFOLD_FILES includes .sf/ANTI-GOALS.md", () => {
	const paths = SCAFFOLD_FILES.map((f) => f.path);
	assert.ok(
		paths.includes(".sf/ANTI-GOALS.md"),
		"SCAFFOLD_FILES should include .sf/ANTI-GOALS.md",
	);
});

test("tacit-knowledge: scaffold template content includes expected headings", () => {
	const principles = SCAFFOLD_FILES.find((f) => f.path === ".sf/PRINCIPLES.md");
	assert.ok(principles, "PRINCIPLES.md template should exist");
	assert.match(principles!.content, /# Principles/);

	const taste = SCAFFOLD_FILES.find((f) => f.path === ".sf/TASTE.md");
	assert.ok(taste, "TASTE.md template should exist");
	assert.match(taste!.content, /# Taste/);

	const antiGoals = SCAFFOLD_FILES.find((f) => f.path === ".sf/ANTI-GOALS.md");
	assert.ok(antiGoals, "ANTI-GOALS.md template should exist");
	assert.match(antiGoals!.content, /# Anti-goals/);
});

// ─── ensureAgenticDocsScaffold creates tacit knowledge files ──────────────────

test("tacit-knowledge: ensureAgenticDocsScaffold creates .sf/PRINCIPLES.md", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		ensureAgenticDocsScaffold(dir);
		const path = join(dir, ".sf", "PRINCIPLES.md");
		assert.ok(existsSync(path), ".sf/PRINCIPLES.md should be created");
		assert.match(readFileSync(path, "utf-8"), /# Principles/);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("tacit-knowledge: ensureAgenticDocsScaffold creates .sf/TASTE.md", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		ensureAgenticDocsScaffold(dir);
		const path = join(dir, ".sf", "TASTE.md");
		assert.ok(existsSync(path), ".sf/TASTE.md should be created");
		assert.match(readFileSync(path, "utf-8"), /# Taste/);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("tacit-knowledge: ensureAgenticDocsScaffold creates .sf/ANTI-GOALS.md", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		ensureAgenticDocsScaffold(dir);
		const path = join(dir, ".sf", "ANTI-GOALS.md");
		assert.ok(existsSync(path), ".sf/ANTI-GOALS.md should be created");
		assert.match(readFileSync(path, "utf-8"), /# Anti-goals/);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

// ─── loadTacitKnowledgeBlock ──────────────────────────────────────────────────

test("loadTacitKnowledgeBlock: returns empty string when .sf/ is missing", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		const result = loadTacitKnowledgeBlock(dir);
		assert.strictEqual(result, "");
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("loadTacitKnowledgeBlock: returns empty string when all three files are missing", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		mkdirSync(join(dir, ".sf"), { recursive: true });
		const result = loadTacitKnowledgeBlock(dir);
		assert.strictEqual(result, "");
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("loadTacitKnowledgeBlock: injects PRINCIPLES.md content when present", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		mkdirSync(join(dir, ".sf"), { recursive: true });
		writeFileSync(
			join(dir, ".sf", "PRINCIPLES.md"),
			"# Principles\n\n- SF stays standalone forever.\n",
			"utf-8",
		);
		const result = loadTacitKnowledgeBlock(dir);
		assert.ok(result.includes("[TACIT KNOWLEDGE"));
		assert.ok(result.includes("## Principles"));
		assert.ok(result.includes("SF stays standalone forever"));
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("loadTacitKnowledgeBlock: injects all three sections when all present", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		mkdirSync(join(dir, ".sf"), { recursive: true });
		writeFileSync(join(dir, ".sf", "PRINCIPLES.md"), "- p1\n", "utf-8");
		writeFileSync(join(dir, ".sf", "TASTE.md"), "- t1\n", "utf-8");
		writeFileSync(join(dir, ".sf", "ANTI-GOALS.md"), "- a1\n", "utf-8");
		const result = loadTacitKnowledgeBlock(dir);
		assert.ok(result.includes("## Principles"));
		assert.ok(result.includes("## Taste"));
		assert.ok(result.includes("## Anti-goals"));
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("loadTacitKnowledgeBlock: strips scaffold markers from content", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		mkdirSync(join(dir, ".sf"), { recursive: true });
		writeFileSync(
			join(dir, ".sf", "PRINCIPLES.md"),
			"# Principles\n\n<!-- sf-scaffold: version=1 hash=abc state=pending -->\n\n- Real content.\n",
			"utf-8",
		);
		const result = loadTacitKnowledgeBlock(dir);
		assert.ok(!result.includes("sf-scaffold"), "scaffold markers should be stripped");
		assert.ok(result.includes("Real content"), "real content should be present");
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});

test("loadTacitKnowledgeBlock: truncates section exceeding 4KB with note", () => {
	const dir = mkdtempSync(join(tmpdir(), "sf-tacit-"));
	try {
		mkdirSync(join(dir, ".sf"), { recursive: true });
		const bigContent = "x".repeat(5000);
		writeFileSync(join(dir, ".sf", "PRINCIPLES.md"), bigContent, "utf-8");
		const result = loadTacitKnowledgeBlock(dir);
		assert.ok(result.includes("truncated"), "should include truncation note");
		// The block should not contain all 5000 x's
		const xCount = (result.match(/x/g) ?? []).length;
		assert.ok(xCount < 5000, "truncated block should be shorter than 5000 chars");
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
});
