import assert from "node:assert/strict";
import { mkdirSync, mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { DatabaseSync } from "node:sqlite";
import { afterEach, beforeEach, test } from "vitest";

import {
	getParallelWorkerDbPath,
	queryParallelRecentCompletionRows,
	queryParallelSliceProgress,
} from "../parallel-monitor-store.js";

let project;

function createWorkerDb(milestoneId) {
	const dbPath = getParallelWorkerDbPath(project, milestoneId);
	mkdirSync(join(project, ".sf", "worktrees", milestoneId, ".sf"), {
		recursive: true,
	});
	const db = new DatabaseSync(dbPath);
	db.exec(`
		CREATE TABLE slices (
			milestone_id TEXT NOT NULL,
			id TEXT NOT NULL,
			status TEXT NOT NULL
		);
		CREATE TABLE tasks (
			milestone_id TEXT NOT NULL,
			slice_id TEXT NOT NULL,
			id TEXT NOT NULL,
			task_status TEXT NOT NULL,
			one_liner TEXT,
			completed_at TEXT
		);
	`);
	return db;
}

beforeEach(() => {
	project = mkdtempSync(join(tmpdir(), "sf-parallel-monitor-store-"));
});

afterEach(() => {
	rmSync(project, { recursive: true, force: true });
});

test("queryParallelSliceProgress_when_worker_db_missing_returns_empty_projection", () => {
	assert.deepEqual(queryParallelSliceProgress(project, "M404"), []);
});

test("queryParallelSliceProgress_reads_task_progress_from_worker_db", () => {
	const db = createWorkerDb("M001");
	try {
		db.prepare(
			"INSERT INTO slices (milestone_id, id, status) VALUES (?, ?, ?)",
		).run("M001", "S01", "running");
		db.prepare(
			"INSERT INTO slices (milestone_id, id, status) VALUES (?, ?, ?)",
		).run("M001", "S02", "complete");
		db.prepare(
			"INSERT INTO tasks (milestone_id, slice_id, id, task_status, one_liner, completed_at) VALUES (?, ?, ?, ?, ?, ?)",
		).run("M001", "S01", "T01", "done", "done", "2026-05-08T01:00:00.000Z");
		db.prepare(
			"INSERT INTO tasks (milestone_id, slice_id, id, task_status, one_liner, completed_at) VALUES (?, ?, ?, ?, ?, ?)",
		).run("M001", "S01", "T02", "todo", "todo", null);
		db.prepare(
			"INSERT INTO tasks (milestone_id, slice_id, id, task_status, one_liner, completed_at) VALUES (?, ?, ?, ?, ?, ?)",
		).run("M001", "S02", "T03", "done", "done", "2026-05-08T02:00:00.000Z");
	} finally {
		db.close();
	}

	assert.deepEqual(queryParallelSliceProgress(project, "M001"), [
		{ id: "S01", status: "running", total: 2, done: 1 },
		{ id: "S02", status: "complete", total: 1, done: 1 },
	]);
});

test("queryParallelRecentCompletionRows_returns_latest_completed_tasks", () => {
	const db = createWorkerDb("M002");
	try {
		db.prepare(
			"INSERT INTO slices (milestone_id, id, status) VALUES (?, ?, ?)",
		).run("M002", "S01", "running");
		for (let i = 0; i < 6; i++) {
			db.prepare(
				"INSERT INTO tasks (milestone_id, slice_id, id, task_status, one_liner, completed_at) VALUES (?, ?, ?, ?, ?, ?)",
			).run(
				"M002",
				"S01",
				`T0${i}`,
				"done",
				`task ${i}`,
				`2026-05-08T0${i}:00:00.000Z`,
			);
		}
		db.prepare(
			"INSERT INTO tasks (milestone_id, slice_id, id, task_status, one_liner, completed_at) VALUES (?, ?, ?, ?, ?, ?)",
		).run("M002", "S01", "T99", "todo", "not done", null);
	} finally {
		db.close();
	}

	const rows = queryParallelRecentCompletionRows(project, "M002", 3);

	assert.deepEqual(
		rows.map((row) => row.taskId),
		["T05", "T04", "T03"],
	);
	assert.deepEqual(rows[0], {
		taskId: "T05",
		sliceId: "S01",
		oneLiner: "task 5",
		completedAt: "2026-05-08T05:00:00.000Z",
	});
});
