/**
 * Tests for skill eval harness.
 *
 * Purpose: verify eval-case materialization and grader execution are stable.
 */

import {
	existsSync,
	mkdirSync,
	mkdtempSync,
	readFileSync,
	rmSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
import {
	createEvalCase,
	generateDefaultEvalCase,
	runGrader,
	runSkillEvals,
} from "../skills/eval-harness.js";

function makeSkillDir() {
	const dir = mkdtempSync(join(tmpdir(), "sf-skill-eval-"));
	mkdirSync(join(dir, ".agents", "skills", "test-skill"), { recursive: true });
	return join(dir, ".agents", "skills", "test-skill");
}

function cleanup(dir) {
	try {
		rmSync(dir, { recursive: true, force: true });
	} catch {
		/* ignore */
	}
}

describe("skill eval harness", () => {
	test("createEvalCase_creates_case_files_and_workspace", () => {
		const skillDir = makeSkillDir();
		try {
			const caseDef = {
				task: "Test task for skill",
				grader:
					"export async function grade() { return { passed: true, score: 1 }; }",
			};
			const result = createEvalCase(skillDir, "case-1", caseDef);
			expect(result.caseName).toBe("case-1");
			expect(existsSync(join(skillDir, "evals", "case-1", "task.md"))).toBe(
				true,
			);
			expect(existsSync(join(skillDir, "evals", "case-1", "grader.js"))).toBe(
				true,
			);
			expect(existsSync(join(skillDir, "evals", "case-1", "work"))).toBe(true);
		} finally {
			cleanup(skillDir);
		}
	});

	test("createEvalCase_with_hidden_reference_writes_fixture", () => {
		const skillDir = makeSkillDir();
		try {
			const caseDef = {
				task: "Test task",
				grader:
					"export async function grade() { return { passed: true, score: 1 }; }",
				hidden: { answer: "expected-output" },
			};
			createEvalCase(skillDir, "case-2", caseDef);
			const hiddenPath = join(
				skillDir,
				"evals",
				"case-2",
				"hidden",
				"reference.json",
			);
			expect(existsSync(hiddenPath)).toBe(true);
			const hidden = JSON.parse(readFileSync(hiddenPath, "utf-8"));
			expect(hidden.answer).toBe("expected-output");
		} finally {
			cleanup(skillDir);
		}
	});

	test("runGrader_returns_error_when_grader_missing", async () => {
		const skillDir = makeSkillDir();
		try {
			mkdirSync(join(skillDir, "evals", "bad-case"), { recursive: true });
			const result = await runGrader(join(skillDir, "evals", "bad-case"), {});
			expect(result.passed).toBe(false);
			expect(result.details[0]).toBe("Grader not found");
		} finally {
			cleanup(skillDir);
		}
	});

	test("generateDefaultEvalCase_mentions_skill_name_and_exported_grader", () => {
		const skill = { name: "forge-test", description: "Test skill" };
		const caseDef = generateDefaultEvalCase(skill);
		expect(caseDef.task.includes("forge-test")).toBe(true);
		expect(caseDef.grader.includes("export async function grade")).toBe(true);
	});

	test("runSkillEvals_returns_empty_summary_without_evals", async () => {
		const skillDir = makeSkillDir();
		try {
			const result = await runSkillEvals(skillDir, {});
			expect(result.totalCases).toBe(0);
			expect(result.passedCases).toBe(0);
		} finally {
			cleanup(skillDir);
		}
	});
});
