import { existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, test } from "vitest";
import {
	checkIntentConflicts,
	clearAllIntents,
	declareIntent,
	getActiveIntents,
	releaseIntent,
} from "../parallel-intent.js";
import { closeDatabase } from "../sf-db.js";

/**
 * Parallel intent registry tests.
 */
function makeBasePath() {
	const dir = mkdtempSync(join(tmpdir(), "sf-intent-"));
	mkdirSync(join(dir, ".sf"), { recursive: true });
	return dir;
}

function cleanup(basePath) {
	try {
		rmSync(basePath, { recursive: true, force: true });
	} catch {
		/* ignore */
	}
}

describe("parallel intent registry", () => {
	let basePath;

	beforeEach(() => {
		basePath = makeBasePath();
	});

	afterEach(() => {
		closeDatabase();
		cleanup(basePath);
		basePath = null;
	});

	test("declareIntent_when_valid_input_records_claim", () => {
		const result = declareIntent(basePath, "M001", [
			"src/foo.ts",
			"src/bar.ts",
		]);
		expect(result.ok).toBe(true);
		const intents = getActiveIntents(basePath);
		expect(intents).toHaveLength(1);
		expect(intents[0].milestoneId).toBe("M001");
		expect(intents[0].files).toEqual(["src/foo.ts", "src/bar.ts"]);
		expect(intents[0].status).toBe("claimed");
		expect(existsSync(join(basePath, ".sf", "parallel"))).toBe(false);
	});

	test("checkIntentConflicts_when_files_overlap_reports_existing_milestone", () => {
		declareIntent(basePath, "M001", ["src/foo.ts", "src/bar.ts"]);
		const conflicts = checkIntentConflicts(basePath, "M002", [
			"src/bar.ts",
			"src/baz.ts",
		]);
		expect(conflicts).toHaveLength(1);
		expect(conflicts[0].milestoneId).toBe("M001");
		expect(conflicts[0].files).toEqual(["src/bar.ts"]);
	});

	test("checkIntentConflicts_when_no_overlap_returns_empty_list", () => {
		declareIntent(basePath, "M001", ["src/foo.ts"]);
		const conflicts = checkIntentConflicts(basePath, "M002", ["src/bar.ts"]);
		expect(conflicts).toHaveLength(0);
	});

	test("releaseIntent_when_known_milestone_clears_active_intent", () => {
		declareIntent(basePath, "M001", ["src/foo.ts"]);
		releaseIntent(basePath, "M001");
		const intents = getActiveIntents(basePath);
		expect(intents).toHaveLength(0);
	});

	test("clearAllIntents_when_multiple_claims_removes_all_records", () => {
		declareIntent(basePath, "M001", ["src/foo.ts"]);
		declareIntent(basePath, "M002", ["src/bar.ts"]);
		clearAllIntents(basePath);
		const intents = getActiveIntents(basePath);
		expect(intents).toHaveLength(0);
	});

	test("getActiveIntents_when_release_exists_ignores_released_records", () => {
		declareIntent(basePath, "M001", ["src/foo.ts"]);
		declareIntent(basePath, "M002", ["src/bar.ts"]);
		releaseIntent(basePath, "M001");
		const intents = getActiveIntents(basePath);
		expect(intents).toHaveLength(1);
		expect(intents[0].milestoneId).toBe("M002");
	});
});
