import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  NodeNotFoundError,
  NodeHasChildrenError,
  NodeHasAssignedCostCentersError,
} from "../lib/errors.generated";
import { rootCostCenterNode, childCostCenterNode, baseCostCenter } from "../testing/fixtures";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./deleteCostCenterHierarchyNode";

describe("deleteCostCenterHierarchyNode", () => {
  it("returns error when node does not exist", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(undefined);

    const result = await run(db, { nodeId: "missing-node" }, commandCtx);

    expectErr(result, NodeNotFoundError);
  });

  it("returns error when node has children", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select
      .mockReturnValueOnce(rootCostCenterNode) // node exists
      .mockReturnValueOnce(childCostCenterNode); // has children

    const result = await run(db, { nodeId: rootCostCenterNode.id }, commandCtx);

    expectErr(result, NodeHasChildrenError);
  });

  it("returns error when node has assigned cost centers", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select
      .mockReturnValueOnce(childCostCenterNode) // node exists
      .mockReturnValueOnce(undefined) // no children
      .mockReturnValueOnce(baseCostCenter); // has assigned cost centers

    const result = await run(db, { nodeId: childCostCenterNode.id }, commandCtx);

    expectErr(result, NodeHasAssignedCostCentersError);
  });

  it("deletes node when it has no children and no assigned cost centers", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select
      .mockReturnValueOnce(childCostCenterNode) // node exists
      .mockReturnValueOnce(undefined) // no children
      .mockReturnValueOnce(undefined); // no assigned cost centers

    const result = await run(db, { nodeId: childCostCenterNode.id }, commandCtx);

    const value = expectOk(result);
    expect(value.nodeId).toBe(childCostCenterNode.id);
    expect(spies.delete).toHaveBeenCalled();
  });
});
