import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { ApHoldAlreadyReleasedError, ApHoldNotFoundError } from "../lib/errors.generated";
import { commandCtx, expectErr, expectOk } from "../testing/commandTestUtils";
import { run } from "./releaseAccountPayableDocumentHold";

const activeHold = {
  id: "ap-hold-1",
  accountPayableDocumentId: "ap-document-1",
  accountPayableDocumentLineId: "ap-document-line-1",
  reasonCode: "INVOICE_UNIT_PRICE_DIFFERS_FROM_PURCHASE_ORDER_UNIT_PRICE",
  source: "SYSTEM",
  releasedAt: null,
  releaseReason: null,
  createdAt: new Date("2024-01-01T00:00:00.000Z"),
  updatedAt: null,
};

describe("releaseAccountPayableDocumentHold", () => {
  it("releases an active hold and sets releasedAt with the release reason", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults(
      [activeHold],
      [
        {
          ...activeHold,
          releasedAt: new Date("2024-02-01T00:00:00.000Z"),
          releaseReason: "approved",
        },
      ],
    );

    const result = await mock.withTx((trx) =>
      run(trx, { id: activeHold.id, releaseReason: "approved" }, commandCtx),
    );

    const value = expectOk(result);
    expect(value.accountPayableDocumentHold.releasedAt).not.toBeNull();
    expect(value.accountPayableDocumentHold.releaseReason).toBe("approved");
  });

  it("returns error when the hold does not exist", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([]);

    const result = await mock.withTx((trx) => run(trx, { id: "missing" }, commandCtx));

    expectErr(result, ApHoldNotFoundError);
  });

  it("returns error when the hold is already released", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([
      {
        ...activeHold,
        releasedAt: new Date("2024-02-01T00:00:00.000Z"),
        releaseReason: "approved",
      },
    ]);

    const result = await mock.withTx((trx) => run(trx, { id: activeHold.id }, commandCtx));

    expectErr(result, ApHoldAlreadyReleasedError);
  });
});
