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

import { validateContent } from "../safety/content-validator.ts";

function withRoadmap(content: string, fn: (path: string) => void): void {
	const dir = mkdtempSync(join(tmpdir(), "sf-content-validator-"));
	try {
		const path = join(dir, "M001-ROADMAP.md");
		writeFileSync(path, content, "utf-8");
		fn(path);
	} finally {
		rmSync(dir, { recursive: true, force: true });
	}
}

function roadmapWithSlices(sliceRows: string[]): string {
	return [
		"# M001: Test",
		"",
		"## Vision",
		"Real work.",
		"",
		"## Vision Alignment Meeting",
		"",
		"### Trigger",
		"Need a plan.",
		"",
		"### Product Manager",
		"Ship useful work.",
		"",
		"### User Advocate",
		"Keep it usable.",
		"",
		"### Customer Panel",
		"Support wants clarity.",
		"",
		"### Business",
		"Reduce risk.",
		"",
		"### Researcher",
		"Comparable systems require this.",
		"",
		"### Delivery Lead",
		"Keep sequence bounded.",
		"",
		"### Partner",
		"The shape is good.",
		"",
		"### Combatant",
		"Watch for stale state.",
		"",
		"### Architect",
		"Persist machine-readable slices.",
		"",
		"### Moderator",
		"Proceed.",
		"",
		"### Weighted Synthesis",
		"This is ready.",
		"",
		"### Confidence By Area",
		"Planning: high.",
		"",
		"### Recommended Route",
		"planning",
		"",
		"## Slice Overview",
		"| ID | Slice | Risk | Depends | Done | After this |",
		"|----|-------|------|---------|------|------------|",
		...sliceRows,
		"",
	].join("\n");
}

test("validateContent accepts Slice Overview table roadmaps", () => {
	withRoadmap(
		roadmapWithSlices([
			"| S01 | First slice | low | - | [ ] | a real slice exists. |",
		]),
		(path) => {
			const violations = validateContent("plan-milestone", path);
			assert.deepEqual(
				violations.filter((v) => /slice\(s\)/.test(v.reason)),
				[],
			);
		},
	);
});

test("validateContent still warns for zero-slice roadmaps", () => {
	withRoadmap(roadmapWithSlices([]), (path) => {
		const violations = validateContent("plan-milestone", path);
		assert.ok(
			violations.some((v) =>
				v.reason.includes("Milestone roadmap has 0 slice(s)"),
			),
		);
	});
});

test("validateContent reports markdownlint structural warnings", () => {
	withRoadmap(
		[
			"# M001: Test",
			"### Skipped Heading Level",
			"Text.",
			"",
			"## Slice Overview",
			"| ID | Slice | Risk | Depends | Done | After this |",
			"|----|-------|------|---------|------|------------|",
			"| S01 | First slice | low | - | [ ] | a real slice exists. |",
			"",
		].join("\n"),
		(path) => {
			const violations = validateContent("plan-milestone", path);
			assert.ok(
				violations.some((v) =>
					v.reason.includes("Markdown lint MD001/heading-increment"),
				),
			);
		},
	);
});

test("validateContent reports literal escaped newline corruption", () => {
	withRoadmap(
		roadmapWithSlices([
			"| S01 | First slice | low | - | [ ] | line one\\nline two |",
		]),
		(path) => {
			const violations = validateContent("plan-milestone", path);
			assert.ok(
				violations.some((v) =>
					v.reason.includes("literal escaped newline text"),
				),
			);
		},
	);
});

test("validateContent reports leaked JSON field syntax in artifacts", () => {
	withRoadmap(
		roadmapWithSlices([
			'| S01 | First slice | low | - | [ ] | proof", "integrationClosure": "bad" |',
		]),
		(path) => {
			const violations = validateContent("plan-milestone", path);
			assert.ok(
				violations.some((v) =>
					v.reason.includes("leaked JSON field syntax"),
				),
			);
		},
	);
});
