import assert from "node:assert/strict";
import {
	existsSync,
	mkdirSync,
	mkdtempSync,
	rmSync,
	writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, test } from "vitest";
import {
	checkEngineHealth,
	normalizeLegacyPlanSlugDirectories,
} from "../doctor-engine-checks.js";
import { closeDatabase, openDatabase } from "../sf-db.js";

const tmpDirs = [];

function makeProject() {
	const dir = mkdtempSync(join(tmpdir(), "sf-plan-dir-"));
	tmpDirs.push(dir);
	mkdirSync(join(dir, ".sf", "milestones"), { recursive: true });
	return dir;
}

afterEach(() => {
	closeDatabase();
	while (tmpDirs.length > 0) {
		const dir = tmpDirs.pop();
		if (dir) rmSync(dir, { recursive: true, force: true });
	}
});

describe("doctor plan directory normalization", () => {
	test("normalizeLegacyPlanSlugDirectories_when_fix_enabled_renames_milestone_and_slice_dirs", () => {
		const project = makeProject();
		const legacySlice = join(
			project,
			".sf",
			"milestones",
			"M001-long-name",
			"slices",
			"S02-research-work",
		);
		mkdirSync(legacySlice, { recursive: true });
		writeFileSync(join(legacySlice, "S02-RESEARCH.md"), "# Research\n");
		const issues = [];
		const fixesApplied = [];

		normalizeLegacyPlanSlugDirectories(
			project,
			issues,
			fixesApplied,
			(code) => code === "legacy_plan_slug_directory",
		);

		assert.equal(existsSync(join(project, ".sf", "milestones", "M001")), true);
		assert.equal(
			existsSync(join(project, ".sf", "milestones", "M001", "slices", "S02")),
			true,
		);
		assert.equal(
			existsSync(join(project, ".sf", "milestones", "M001-long-name")),
			false,
		);
		assert.equal(
			existsSync(
				join(
					project,
					".sf",
					"milestones",
					"M001",
					"slices",
					"S02-research-work",
				),
			),
			false,
		);
		assert.equal(
			issues.filter((issue) => issue.code === "legacy_plan_slug_directory")
				.length,
			2,
		);
		assert.equal(fixesApplied.length, 2);
	});

	test("normalizeLegacyPlanSlugDirectories_when_target_exists_reports_conflict_without_rename", () => {
		const project = makeProject();
		mkdirSync(join(project, ".sf", "milestones", "M001"), { recursive: true });
		mkdirSync(join(project, ".sf", "milestones", "M001-long-name"), {
			recursive: true,
		});
		const issues = [];
		const fixesApplied = [];

		normalizeLegacyPlanSlugDirectories(
			project,
			issues,
			fixesApplied,
			(code) => code === "legacy_plan_slug_directory",
		);

		assert.equal(
			issues.some(
				(candidate) => candidate.code === "legacy_plan_slug_directory",
			),
			false,
		);
		assert.equal(
			existsSync(join(project, ".sf", "milestones", "M001-long-name")),
			true,
		);
		assert.deepEqual(fixesApplied, []);
	});

	test("checkEngineHealth_when_db_file_can_open_does_not_report_unavailable", async () => {
		const project = makeProject();
		const dbPath = join(project, ".sf", "sf.db");
		assert.equal(openDatabase(dbPath), true);
		closeDatabase();
		const issues = [];

		await checkEngineHealth(project, issues, [], () => false);

		assert.equal(
			issues.some((issue) => issue.code === "db_unavailable"),
			false,
		);
	});
});
