import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { InvalidInvoiceLineError, InvoiceNotEditableError } from "../lib/errors.generated";
import {
  baseInvoiceLineInput,
  baseSalesInvoice,
  baseSalesInvoiceLine,
  baseSalesOrderLine,
  issuedSalesInvoice,
} from "../testing/fixtures";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./updateSalesInvoice";

describe("updateSalesInvoice", () => {
  it("updates draft invoice metadata", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const orderLine = { ...baseSalesOrderLine, salesOrderId: baseSalesInvoice.salesOrderId };
    spies.select
      .mockReturnValueOnce(baseSalesInvoice)
      .mockReturnValueOnce(orderLine)
      .mockReturnValueOnce(orderLine);
    spies.update.mockReturnValueOnce({
      ...baseSalesInvoice,
      notes: "Updated",
      updatedAt: new Date(),
    });
    spies.insert.mockReturnValueOnce(baseSalesInvoiceLine);

    const result = await run(
      db,
      {
        salesInvoiceId: baseSalesInvoice.id,
        notes: "Updated",
        lines: [baseInvoiceLineInput],
      },
      commandCtx,
    );

    expectOk(result);
    expect(spies.delete).toHaveBeenCalled();
    expect(spies.set).toHaveBeenCalledWith(expect.objectContaining({ notes: "Updated" }));
  });

  it("returns error when updating an issued invoice", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(issuedSalesInvoice);

    const result = await run(
      db,
      { salesInvoiceId: issuedSalesInvoice.id, notes: "Updated" },
      commandCtx,
    );

    expectErr(result, InvoiceNotEditableError);
  });

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

    const result = await run(
      db,
      {
        salesInvoiceId: baseSalesInvoice.id,
        lines: [{ ...baseInvoiceLineInput, quantity: 0 }],
      },
      commandCtx,
    );

    expectErr(result, InvalidInvoiceLineError);
  });
});
