import { describe, expect, it } from "vitest";
import { unsafeOpaqueId, type PlanRevisionId, type ProjectId, type TaskId } from "@awp/contracts";
import {
  DependencyCycleError,
  InvalidDependencyError,
  validateTaskDependencies,
  type Task,
} from "@awp/domain";
const project = unsafeOpaqueId<ProjectId>("project");
const rev = unsafeOpaqueId<PlanRevisionId>("revision");
const t = (id: string, deps: string[] = [], status: Task["status"] = "planned"): Task => ({
  id: unsafeOpaqueId<TaskId>(id),
  projectId: project,
  planRevisionId: rev,
  title: id,
  status,
  dependencyIds: deps.map((x) => unsafeOpaqueId<TaskId>(x)),
  revision: 1,
});
describe("task dependency DAG", () => {
  it("accepts cross-plan-style acyclic dependencies within one Project", () => {
    expect(() =>
      validateTaskDependencies([t("a"), t("b", ["a"]), t("c", ["a"]), t("d", ["b", "c"])]),
    ).not.toThrow();
  });
  it("rejects a cycle with a readable path", () => {
    expect(() =>
      validateTaskDependencies([t("a", ["c"]), t("b", ["a"]), t("c", ["b"])]),
    ).toThrowError(
      new DependencyCycleError([
        unsafeOpaqueId<TaskId>("a"),
        unsafeOpaqueId<TaskId>("c"),
        unsafeOpaqueId<TaskId>("b"),
        unsafeOpaqueId<TaskId>("a"),
      ]),
    );
  });
  it("rejects unknown prerequisites", () => {
    expect(() => validateTaskDependencies([t("a", ["missing"])])).toThrow(InvalidDependencyError);
  });
});
