import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  CostCenterNotFoundError,
  InvalidCategoryError,
  InvalidValidityPeriodError,
  InvalidNameError,
} from "../lib/errors.generated";
import { baseCostCenter } from "../testing/fixtures";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./updateCostCenter";

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

    const result = await run(db, { costCenterId: "missing-cc", name: "Updated" }, commandCtx);

    expectErr(result, CostCenterNotFoundError);
  });

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

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

    expectErr(result, InvalidNameError);
  });

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

    const result = await run(
      db,
      { costCenterId: baseCostCenter.id, category: "not-a-category" },
      commandCtx,
    );

    expectErr(result, InvalidCategoryError);
  });

  it("returns error when validTo is before validFrom", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCostCenter);

    const result = await run(
      db,
      {
        costCenterId: baseCostCenter.id,
        validFrom: new Date("2025-12-31"),
        validTo: new Date("2024-01-01"),
      },
      commandCtx,
    );

    expectErr(result, InvalidValidityPeriodError);
  });

  it("updates cost center with valid fields", async () => {
    const updatedCc = { ...baseCostCenter, name: "Updated Name", updatedAt: new Date() };
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCostCenter);
    spies.update.mockReturnValueOnce(updatedCc);

    const result = await run(
      db,
      { costCenterId: baseCostCenter.id, name: "Updated Name" },
      commandCtx,
    );

    const value = expectOk(result);
    expect(value.costCenter.name).toBe("Updated Name");
  });

  it("updates multiple fields at once", async () => {
    const updatedCc = {
      ...baseCostCenter,
      name: "New Name",
      category: "sales",
      description: "New desc",
      updatedAt: new Date(),
    };
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseCostCenter);
    spies.update.mockReturnValueOnce(updatedCc);

    const result = await run(
      db,
      {
        costCenterId: baseCostCenter.id,
        name: "New Name",
        category: "sales",
        description: "New desc",
      },
      commandCtx,
    );

    const value = expectOk(result);
    expect(value.costCenter).toEqual(updatedCc);
  });
});
