import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { DB } from "../generated/kysely-tailordb";
import { basePurchaseBill, basePurchaseBillLines, matchedPurchaseBill } from "../testing/fixtures";
import { expectOk } from "../testing/commandTestUtils";
import { run } from "./getPurchaseBill";

describe("getPurchaseBill", () => {
  it("returns purchase bill when found by id", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(basePurchaseBill);

    const result = await run(db, { id: basePurchaseBill.id });
    const { purchaseBill } = expectOk<{ purchaseBill: unknown }>(result as never);

    expect(purchaseBill).not.toBeNull();
    expect(purchaseBill).toMatchObject({
      id: basePurchaseBill.id,
      lines: basePurchaseBillLines,
    });
  });

  it("returns purchase bill when found by supplier invoice identity", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(basePurchaseBill);

    const result = await run(db, {
      companyId: basePurchaseBill.companyId,
      supplierId: basePurchaseBill.supplierId,
      invoiceNumber: basePurchaseBill.invoiceNumber,
    });
    const { purchaseBill } = expectOk<{ purchaseBill: unknown }>(result as never);

    expect(purchaseBill).not.toBeNull();
    expect(purchaseBill).toMatchObject({
      id: basePurchaseBill.id,
      companyId: basePurchaseBill.companyId,
      supplierId: basePurchaseBill.supplierId,
      invoiceNumber: basePurchaseBill.invoiceNumber,
    });
  });

  it("returns matching outcome and due schedule with the bill", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(matchedPurchaseBill);

    const result = await run(db, { id: matchedPurchaseBill.id });
    const { purchaseBill } = expectOk<{
      purchaseBill: {
        matchingMode: string;
        dueSchedule: { dueDate: Date; amount: number }[];
      };
    }>(result as never);

    expect(purchaseBill.matchingMode).toBe("TWO_WAY");
    expect(purchaseBill.dueSchedule).toHaveLength(1);
    expect(purchaseBill.dueSchedule[0]).toMatchObject({ amount: 440 });
  });

  it("returns null when purchase bill is not found", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(undefined);

    const result = await run(db, { id: "nonexistent-id" });
    const { purchaseBill } = expectOk<{ purchaseBill: null }>(result as never);

    expect(purchaseBill).toBeNull();
  });
});
