import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  PurchaseBillNotCancellableError,
  PurchaseBillNotFoundError,
} from "../lib/errors.generated";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { basePurchaseBill, blockedPurchaseBill } from "../testing/fixtures";
import { run } from "./cancelPurchaseBill";

describe("cancelPurchaseBill", () => {
  it("cancels a draft purchase bill", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(basePurchaseBill); // PurchaseBill
    spies.update.mockReturnValueOnce({ ...basePurchaseBill, status: "CANCELLED" }); // update PurchaseBill
    expectOk(await run(db, { id: basePurchaseBill.id }, commandCtx));
  });

  it("cancels a blocked purchase bill", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(blockedPurchaseBill); // PurchaseBill
    spies.update.mockReturnValueOnce({ ...blockedPurchaseBill, status: "CANCELLED" }); // update PurchaseBill
    expectOk(await run(db, { id: blockedPurchaseBill.id }, commandCtx));
  });

  it("preserves variance evidence when a blocked bill is cancelled", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(blockedPurchaseBill); // PurchaseBill
    spies.update.mockReturnValueOnce({ ...blockedPurchaseBill, status: "CANCELLED" }); // update PurchaseBill

    await run(db, { id: blockedPurchaseBill.id }, commandCtx);

    const setCall = spies.set.mock.calls[0]?.[0] as Record<string, unknown>;
    expect(setCall).not.toHaveProperty("varianceReason");
  });

  it("returns error when purchase bill does not exist", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(undefined);
    expectErr(await run(db, { id: "missing-bill" }, commandCtx), PurchaseBillNotFoundError);
  });

  it("returns error when purchase bill status does not allow cancellation", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce({ ...basePurchaseBill, status: "MATCHED" });
    expectErr(
      await run(db, { id: basePurchaseBill.id }, commandCtx),
      PurchaseBillNotCancellableError,
    );
  });
});
