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, test } from "vitest";
import { handleBacklog } from "../commands-backlog.js";
import { closeDatabase, listBacklogItems, openDatabase } from "../sf-db.js";

const tmpRoots = [];

afterEach(() => {
	closeDatabase();
	for (const root of tmpRoots.splice(0)) {
		rmSync(root, { recursive: true, force: true });
	}
});

function makeProject() {
	const root = mkdtempSync(join(tmpdir(), "sf-backlog-db-"));
	tmpRoots.push(root);
	return root;
}

function makeCtx(messages) {
	return {
		ui: {
			notify(message, level) {
				messages.push({ message, level });
			},
		},
	};
}

test("backlog_add_when_db_available_persists_without_work_queue_markdown", async () => {
	const project = makeProject();
	mkdirSync(join(project, ".sf"), { recursive: true });
	openDatabase(join(project, ".sf", "sf.db"));
	const previousCwd = process.cwd();
	const messages = [];
	try {
		process.chdir(project);
		await handleBacklog("add Fix dispatch priority", makeCtx(messages), null);
	} finally {
		process.chdir(previousCwd);
	}

	const items = listBacklogItems();
	assert.equal(items.length, 1);
	assert.equal(items[0].id, "999.1");
	assert.equal(items[0].title, "Fix dispatch priority");
	assert.equal(items[0].status, "pending");
	assert.equal(existsSync(join(project, ".sf", "WORK-QUEUE.md")), false);
	assert.equal(messages.at(-1).level, "success");
});

test("backlog_list_when_work_queue_markdown_exists_ignores_it_and_uses_db", async () => {
	const project = makeProject();
	const sfDir = join(project, ".sf");
	mkdirSync(sfDir, { recursive: true });
	writeFileSync(
		join(sfDir, "WORK-QUEUE.md"),
		"# Backlog\n\n- [ ] 999.7 — Legacy item (added 2026-05-07)\n",
		"utf-8",
	);
	openDatabase(join(project, ".sf", "sf.db"));
	const previousCwd = process.cwd();
	const messages = [];
	try {
		process.chdir(project);
		await handleBacklog("", makeCtx(messages), null);
		await handleBacklog("", makeCtx(messages), null);
	} finally {
		process.chdir(previousCwd);
	}

	const items = listBacklogItems();
	assert.equal(items.length, 0);
	assert.match(messages.at(-1).message, /Backlog is empty/);
});

test("backlog_add_when_switching_projects_uses_current_project_db", async () => {
	const first = makeProject();
	const second = makeProject();
	mkdirSync(join(first, ".sf"), { recursive: true });
	mkdirSync(join(second, ".sf"), { recursive: true });
	const previousCwd = process.cwd();
	try {
		process.chdir(first);
		await handleBacklog("add First project item", makeCtx([]), null);
		process.chdir(second);
		await handleBacklog("add Second project item", makeCtx([]), null);
	} finally {
		process.chdir(previousCwd);
	}

	closeDatabase();
	openDatabase(join(first, ".sf", "sf.db"));
	assert.deepEqual(
		listBacklogItems().map((item) => item.title),
		["First project item"],
	);
	closeDatabase();
	openDatabase(join(second, ".sf", "sf.db"));
	assert.deepEqual(
		listBacklogItems().map((item) => item.title),
		["Second project item"],
	);
});
