import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { CompanyNotFoundError, InvalidNameError } from "../lib/errors.generated";
import { baseCompany, baseCostCenterHierarchy } from "../testing/fixtures";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./createCostCenterHierarchy";

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

    const result = await run(
      db,
      { companyId: "missing-company", name: "Hierarchy", version: "V1" },
      commandCtx,
    );

    expectErr(result, CompanyNotFoundError);
  });

  it("returns error when company is not ACTIVE", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce({ ...baseCompany, status: "INACTIVE" });

    const result = await run(
      db,
      { companyId: baseCompany.id, name: "Hierarchy", version: "V1" },
      commandCtx,
    );

    expectErr(result, CompanyNotFoundError);
  });

  it("returns error when name is empty", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);

    const result = await run(
      db,
      { companyId: baseCompany.id, name: "", version: "V1" },
      commandCtx,
    );

    expectErr(result, InvalidNameError);
  });

  it("returns error when name is whitespace only", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);

    const result = await run(
      db,
      { companyId: baseCompany.id, name: "   ", version: "V1" },
      commandCtx,
    );

    expectErr(result, InvalidNameError);
  });

  it("creates hierarchy with valid inputs", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);
    spies.insert.mockReturnValueOnce(baseCostCenterHierarchy);

    const result = await run(
      db,
      { companyId: baseCompany.id, name: "Standard Hierarchy", version: "V1" },
      commandCtx,
    );

    const value = expectOk(result);
    expect(value.hierarchy).toEqual(baseCostCenterHierarchy);
  });

  it("emits audit event by calling insert", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);
    spies.insert.mockReturnValueOnce(baseCostCenterHierarchy);

    const result = await run(
      db,
      { companyId: baseCompany.id, name: "Standard Hierarchy", version: "V1" },
      commandCtx,
    );

    expectOk(result);
    expect(spies.insert).toHaveBeenCalled();
  });
});
