import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { CoNotDraftError, CoNotFoundError } from "../lib/errors.generated";
import { basePurchaseChangeOrder, submittedChangeOrder } from "../testing/fixtures";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./updatePurchaseChangeOrder";

describe("updatePurchaseChangeOrder", () => {
  it("updates reason on a draft change order", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const updated = { ...basePurchaseChangeOrder, reason: "New reason" };
    spies.select.mockReturnValueOnce(basePurchaseChangeOrder); // selectOne CO
    spies.update.mockReturnValueOnce(updated);

    const result = await run(
      db,
      { id: basePurchaseChangeOrder.id, reason: "New reason" },
      commandCtx,
    );

    expect(expectOk(result).changeOrder.reason).toBe("New reason");
  });

  it("replaces change order lines on an existing draft change order", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const updated = { ...basePurchaseChangeOrder };
    spies.select.mockReturnValueOnce(basePurchaseChangeOrder);
    spies.update.mockReturnValueOnce(updated);
    // delete old lines returns undefined
    // insert new lines returns undefined

    const result = await run(
      db,
      {
        id: basePurchaseChangeOrder.id,
        lines: [{ action: "ADD" as const, itemId: "item-new", quantity: "50", unitPrice: "200" }],
      },
      commandCtx,
    );

    expectOk(result);
    // Verify delete was called (for old lines)
    expect(spies.delete).toHaveBeenCalledTimes(1);
  });

  it("removes all change order lines when empty array is provided", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const updated = { ...basePurchaseChangeOrder };
    spies.select.mockReturnValueOnce(basePurchaseChangeOrder);
    spies.update.mockReturnValueOnce(updated);

    const result = await run(db, { id: basePurchaseChangeOrder.id, lines: [] }, commandCtx);

    expectOk(result);
    // Delete should be called but insert should not be called for lines
    expect(spies.delete).toHaveBeenCalledTimes(1);
  });

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

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

    expectErr(result, CoNotFoundError);
  });

  it("returns error when change order is not in DRAFT status", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(submittedChangeOrder);

    const result = await run(db, { id: submittedChangeOrder.id, reason: "Try" }, commandCtx);

    expectErr(result, CoNotDraftError);
  });
});
