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, baseProfitCenterHierarchy } from "../testing/fixtures";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./createProfitCenterHierarchy";

describe("createProfitCenterHierarchy", () => {
  it("creates a profit center hierarchy with name and company reference", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);
    spies.insert.mockReturnValueOnce(baseProfitCenterHierarchy);

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

    const value = expectOk(result);
    expect(value.profitCenterHierarchy).toEqual(baseProfitCenterHierarchy);
  });

  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: "Test" }, 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: "Test" }, commandCtx);

    expectErr(result, CompanyNotFoundError);
  });

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

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

    expectErr(result, InvalidNameError);
  });

  it("hierarchies from different companies are isolated", async () => {
    const companyB = { id: "company-2", status: "ACTIVE" };
    const hierarchyB = {
      ...baseProfitCenterHierarchy,
      id: "pc-hierarchy-b",
      companyId: companyB.id,
    };
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(companyB);
    spies.insert.mockReturnValueOnce(hierarchyB);

    const result = await run(db, { companyId: companyB.id, name: "Product Lines B" }, commandCtx);

    const value = expectOk(result);
    expect(value.profitCenterHierarchy.companyId).toBe(companyB.id);
  });

  it("a company can have multiple profit center hierarchies", async () => {
    const secondHierarchy = {
      ...baseProfitCenterHierarchy,
      id: "pc-hierarchy-2",
      name: "Regional",
    };
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);
    spies.insert.mockReturnValueOnce(secondHierarchy);

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

    const value = expectOk(result);
    expect(value.profitCenterHierarchy.name).toBe("Regional");
  });

  it("emits audit event recording acting user, timestamp, and initial field values", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCompany);
    spies.insert.mockReturnValueOnce(baseProfitCenterHierarchy);

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

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