/**
 * Unit tests for auto-prompts pure helpers:
 *   - extractMarkdownSection: H2-section extraction from markdown
 *   - buildSliceSummaryExcerpt: structured excerpt from a slice SUMMARY file
 *
 * Both functions are pure-ish (no DB, no network); tests write temp files
 * only when buildSliceSummaryExcerpt needs an absPath on disk.
 */

import assert from "node:assert/strict";
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { test } from 'vitest';
import {
	buildSliceSummaryExcerpt,
	extractMarkdownSection,
} from "../auto-prompts.ts";

// ─── extractMarkdownSection ──────────────────────────────────────────────────

test("extractMarkdownSection: returns body of a matching H2 section", () => {
	const content = `# Title\n\n## Diagnostics\nsome diag text\n\n## Other\nother text\n`;
	const result = extractMarkdownSection(content, "Diagnostics");
	assert.equal(result, "some diag text");
});

test("extractMarkdownSection: returns null when section is absent", () => {
	const content = `## Present\ncontent here\n`;
	assert.equal(extractMarkdownSection(content, "Missing"), null);
});

test("extractMarkdownSection: stops at the next H2 heading", () => {
	const content = `## Alpha\nalpha body\n\n## Beta\nbeta body\n`;
	const result = extractMarkdownSection(content, "Alpha");
	assert.equal(result, "alpha body");
	assert.ok(!result?.includes("beta"), "must not bleed into Beta section");
});

test("extractMarkdownSection: returns trimmed content (no leading/trailing whitespace)", () => {
	const content = `## Verification\n\n  trimmed text  \n\n`;
	const result = extractMarkdownSection(content, "Verification");
	assert.equal(result, "trimmed text");
});

test("extractMarkdownSection: last section (no following H2) returns to EOF", () => {
	const content = `## Final\nfinal content here\n`;
	const result = extractMarkdownSection(content, "Final");
	assert.equal(result, "final content here");
});

test("extractMarkdownSection: heading match is case-sensitive", () => {
	const content = `## diagnostics\nlower case heading\n`;
	// Must NOT match uppercase "Diagnostics"
	assert.equal(extractMarkdownSection(content, "Diagnostics"), null);
	assert.equal(extractMarkdownSection(content, "diagnostics"), "lower case heading");
});

test("extractMarkdownSection: heading with special regex chars is handled safely", () => {
	// Heading contains . and * which would break an unescaped regex
	const content = `## node_modules (*.js)\ncontent\n`;
	const result = extractMarkdownSection(content, "node_modules (*.js)");
	assert.equal(result, "content");
});

// ─── buildSliceSummaryExcerpt ─────────────────────────────────────────────────

function makeTmpDir(prefix: string): string {
	const dir = join(tmpdir(), `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}`);
	mkdirSync(dir, { recursive: true });
	return dir;
}

const MINIMAL_SUMMARY = `---
id: M001/S01/T03
parent: M001/S01
milestone: M001
provides: []
requires: []
affects: []
key_files: []
key_decisions: []
patterns_established: []
drill_down_paths: []
observability_surfaces: []
duration: 3m
verification_result: pass
completed_at: "2026-01-01T00:00:00Z"
blocker_discovered: false
---

# Add Authentication Module

**Implemented JWT-based authentication with refresh tokens.**

## What Happened
Wired up the auth middleware.

## Deviations
None.

## Follow-ups
Write integration tests.
`;

test("buildSliceSummaryExcerpt: happy path — returns header and structured fields", async () => {
	const tmp = makeTmpDir("ap-excerpt-happy");
	try {
		const filePath = join(tmp, "T03-SUMMARY.md");
		writeFileSync(filePath, MINIMAL_SUMMARY, "utf-8");

		const result = await buildSliceSummaryExcerpt(filePath, ".sf/milestones/M001/slices/S01/T03-SUMMARY.md", "S01/T03");

		assert.ok(result.includes("S01/T03 Summary (excerpt)"), "header must include sid");
		assert.ok(result.includes("Add Authentication Module"), "title must appear");
		assert.ok(result.includes("**Verification:** `pass`"), "verification result must appear");
		assert.ok(result.includes("**Blockers:** none"), "blockers line must appear");
		assert.ok(result.includes("**Duration:** 3m"), "duration must appear");
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("buildSliceSummaryExcerpt: missing file returns not-found notice", async () => {
	const result = await buildSliceSummaryExcerpt(
		"/nonexistent/path/T03-SUMMARY.md",
		".sf/milestones/M001/slices/S01/T03-SUMMARY.md",
		"S01/T03",
	);

	assert.ok(result.includes("not found"), "must mention not found for missing file");
	assert.ok(result.includes("S01/T03"), "header must still include sid");
});

test("buildSliceSummaryExcerpt: null absPath returns not-found notice", async () => {
	const result = await buildSliceSummaryExcerpt(
		null,
		".sf/milestones/M001/slices/S01/T03-SUMMARY.md",
		"S01/T03",
	);

	assert.ok(result.includes("not found"), "null absPath must yield not-found notice");
});

test("buildSliceSummaryExcerpt: file without frontmatter id falls back to full inline", async () => {
	const tmp = makeTmpDir("ap-excerpt-nofm");
	try {
		const filePath = join(tmp, "T01-SUMMARY.md");
		// No frontmatter at all — parseSummary returns empty id
		writeFileSync(filePath, "# Raw Summary\n\nSome unstructured text.", "utf-8");

		const result = await buildSliceSummaryExcerpt(filePath, ".sf/m/s/T01-SUMMARY.md", "S01/T01");

		// Fallback: full content inlined, no excerpt header
		assert.ok(result.includes("Some unstructured text"), "must inline full content on fallback");
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});

test("buildSliceSummaryExcerpt: blocker_discovered=true surfaces warning text", async () => {
	const tmp = makeTmpDir("ap-excerpt-blocker");
	try {
		const summaryWithBlocker = MINIMAL_SUMMARY.replace(
			"blocker_discovered: false",
			"blocker_discovered: true",
		);
		const filePath = join(tmp, "T04-SUMMARY.md");
		writeFileSync(filePath, summaryWithBlocker, "utf-8");

		const result = await buildSliceSummaryExcerpt(filePath, ".sf/m/s/T04-SUMMARY.md", "S01/T04");

		assert.ok(result.includes("⚠️ blocker recorded"), "blocker warning must appear");
	} finally {
		rmSync(tmp, { recursive: true, force: true });
	}
});
