/**
 * prompt-loader-fragments.test.mjs — fragment include resolution contracts.
 *
 * Purpose: verify that {{include:name}} directives in prompt templates are
 * resolved before variable validation so fragment-provided placeholder text
 * participates in normal {{var}} substitution.
 *
 * Consumer: prompt-loader.js warmCache + loadPrompt.
 */
import { rmSync, writeFileSync } from "node:fs";
import { join } from "node:path";
import { afterEach, describe, expect, test } from "vitest";
import { loadPrompt } from "../prompt-loader.js";

const promptsDir = join(import.meta.dirname, "..", "prompts");
const fragmentsDir = join(promptsDir, "fragments");

// Temp fixture files written during tests — cleaned up in afterEach.
const tempFiles = [];

function writeFixturePrompt(name, content) {
	const path = join(promptsDir, `${name}.md`);
	writeFileSync(path, content);
	tempFiles.push(path);
	return name;
}

function writeFixtureFragment(name, content) {
	const path = join(fragmentsDir, `${name}.md`);
	writeFileSync(path, content);
	tempFiles.push(path);
	return name;
}

afterEach(() => {
	for (const p of tempFiles.splice(0)) rmSync(p, { force: true });
});

describe("fragment include resolution", () => {
	test("fragment_resolved_and_var_substituted_in_one_pass", () => {
		// Write a minimal fragment and a minimal prompt that includes it.
		writeFixtureFragment(
			"testfrag-wd-simple",
			"## WD\n\nPath: `{{workingDirectory}}`.",
		);
		writeFixturePrompt(
			"testprompt-include-simple",
			"{{include:testfrag-wd-simple}}\n",
		);

		const result = loadPrompt("testprompt-include-simple", {
			workingDirectory: "/my/project",
		});

		expect(result).toContain("## WD");
		expect(result).toContain("`/my/project`");
	});

	test("working_directory_fragment_resolves_in_real_prompt", () => {
		// Use a real migrated prompt that includes {{include:working-directory}}.
		// Write a minimal wrapper prompt so we control the exact var set.
		writeFixturePrompt(
			"testprompt-wd-real",
			"# Header\n\n{{include:working-directory}}\n",
		);

		const result = loadPrompt("testprompt-wd-real", {
			workingDirectory: "/real/path",
		});

		expect(result).toContain("## Working Directory");
		expect(result).toContain("`/real/path`");
		expect(result).toContain("Do NOT `cd` to any other directory");
	});

	test("ops_fragment_omits_no_cd_restriction", () => {
		writeFixturePrompt(
			"testprompt-wd-ops",
			"# Header\n\n{{include:working-directory-ops}}\n",
		);

		const result = loadPrompt("testprompt-wd-ops", {
			workingDirectory: "/ops/path",
		});

		expect(result).toContain("## Working Directory");
		expect(result).toContain("`/ops/path`");
		expect(result).not.toContain("Do NOT `cd`");
	});

	test("unknown_fragment_throws_parse_error", () => {
		writeFixturePrompt(
			"testprompt-unknown-frag",
			"{{include:this-fragment-does-not-exist-xyzzy}}\n",
		);

		expect(() => loadPrompt("testprompt-unknown-frag", {})).toThrow(
			/unknown fragment.*this-fragment-does-not-exist-xyzzy/,
		);
	});

	test("prompts_without_includes_unaffected", () => {
		// A plain template with no {{include:}} must still load and substitute cleanly.
		writeFixturePrompt(
			"testprompt-no-include",
			"# Plain\n\nValue: {{someVar}}.\n",
		);

		const result = loadPrompt("testprompt-no-include", { someVar: "hello" });

		expect(result).toBe("# Plain\n\nValue: hello.");
		expect(result).not.toContain("{{include:");
	});
});
