/**
 * task-frontmatter.test.mjs — Task metadata contract tests.
 *
 * Purpose: verify the DB-backed task frontmatter helper keeps task lifecycle
 * status separate from scheduler lifecycle status.
 */

import assert from "node:assert/strict";
import { test } from "vitest";
import {
	buildTaskRecord,
	canRunInParallel,
	computeTaskPriority,
	DEFAULT_TASK_FRONTMATTER,
	normalizeSchedulerStatus,
	normalizeTaskStatus,
	validateTaskFrontmatter,
} from "../task-frontmatter.js";

test("validateTaskFrontmatter_defaults_are_canonical", () => {
	const result = validateTaskFrontmatter({});
	assert.equal(result.valid, true);
	assert.equal(result.errors.length, 0);
	assert.equal(result.normalized.taskStatus, "todo");
	assert.equal(result.normalized.schedulerStatus, "queued");
});

test("validateTaskFrontmatter_valid_fields_normalize", () => {
	const result = validateTaskFrontmatter({
		risk: "high",
		mutationScope: "cross-cutting",
		verification: "test",
		planApproval: "approved",
		taskStatus: "verifying",
		schedulerStatus: "dispatched",
		estimatedEffort: 120,
		keyFiles: ["src/foo.ts", "src/bar.ts"],
		dependencies: ["T01"],
		blocksParallel: true,
		maxRetries: 3,
	});
	assert.equal(result.valid, true);
	assert.equal(result.normalized.taskStatus, "verifying");
	assert.equal(result.normalized.schedulerStatus, "dispatched");
	assert.deepEqual(result.normalized.keyFiles, ["src/foo.ts", "src/bar.ts"]);
	assert.equal(result.normalized.maxRetries, 3);
});

test("validateTaskFrontmatter_rejects_invalid_choices", () => {
	assert.equal(validateTaskFrontmatter({ risk: "extreme" }).valid, false);
	assert.equal(
		validateTaskFrontmatter({ mutationScope: "everything" }).valid,
		false,
	);
	assert.equal(validateTaskFrontmatter({ taskStatus: "queued" }).valid, false);
	assert.equal(
		validateTaskFrontmatter({ schedulerStatus: "todo" }).valid,
		false,
	);
});

test("task_and_scheduler_status_normalizers_keep_lifecycles_separate", () => {
	assert.equal(normalizeTaskStatus("in_progress"), "running");
	assert.equal(normalizeTaskStatus("manual-attention"), "reviewing");
	assert.equal(normalizeTaskStatus("completed"), "done");
	assert.equal(normalizeSchedulerStatus("pending"), "queued");
	assert.equal(normalizeSchedulerStatus("done"), "consumed");
});

test("buildTaskRecord_attaches_frontmatter", () => {
	const record = buildTaskRecord({
		id: "T01",
		title: "Test task",
		risk: "medium",
		mutation_scope: "bounded",
		status: "in_progress",
	});
	assert.equal(record.frontmatter.risk, "medium");
	assert.equal(record.frontmatter.mutationScope, "bounded");
	assert.equal(record.frontmatter.taskStatus, "running");
	assert.equal(record.frontmatterValid, true);
});

test("canRunInParallel_low_risk_disjoint_files_passes", () => {
	const taskA = {
		frontmatter: {
			...DEFAULT_TASK_FRONTMATTER,
			risk: "low",
			keyFiles: ["src/a.ts"],
		},
	};
	const taskB = {
		frontmatter: {
			...DEFAULT_TASK_FRONTMATTER,
			risk: "low",
			keyFiles: ["src/b.ts"],
		},
	};
	assert.equal(canRunInParallel(taskA, taskB).canParallel, true);
});

test("canRunInParallel_file_overlap_blocks", () => {
	const taskA = {
		frontmatter: { ...DEFAULT_TASK_FRONTMATTER, keyFiles: ["src/shared.ts"] },
	};
	const taskB = {
		frontmatter: { ...DEFAULT_TASK_FRONTMATTER, keyFiles: ["src/shared.ts"] },
	};
	const result = canRunInParallel(taskA, taskB);
	assert.equal(result.canParallel, false);
	assert.match(result.reason, /overlap/i);
});

test("canRunInParallel_blocks_parallel_and_high_risk_pairs_block", () => {
	assert.equal(
		canRunInParallel(
			{ frontmatter: { ...DEFAULT_TASK_FRONTMATTER, blocksParallel: true } },
			{ frontmatter: { ...DEFAULT_TASK_FRONTMATTER } },
		).canParallel,
		false,
	);
	assert.equal(
		canRunInParallel(
			{ frontmatter: { ...DEFAULT_TASK_FRONTMATTER, risk: "high" } },
			{ frontmatter: { ...DEFAULT_TASK_FRONTMATTER, risk: "high" } },
		).canParallel,
		false,
	);
});

test("computeTaskPriority_prioritizes_critical_and_systemic_work", () => {
	const lowRisk = { frontmatter: { ...DEFAULT_TASK_FRONTMATTER, risk: "low" } };
	const critical = {
		frontmatter: { ...DEFAULT_TASK_FRONTMATTER, risk: "critical" },
	};
	const isolated = {
		frontmatter: { ...DEFAULT_TASK_FRONTMATTER, mutationScope: "isolated" },
	};
	const systemic = {
		frontmatter: { ...DEFAULT_TASK_FRONTMATTER, mutationScope: "systemic" },
	};
	assert.ok(computeTaskPriority(critical) > computeTaskPriority(lowRisk));
	assert.ok(computeTaskPriority(systemic) > computeTaskPriority(isolated));
});
