import type { CommandContext } from "@tailor-platform/erp-kit/core";
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { TransferOrderInTransitError } from "../lib/errors.generated";
import { expectErr, expectOk } from "../testing/commandTestUtils";
import {
  baseDraftTransferOrder,
  baseOpenTransferOrder,
  partiallyReceivedTransferOrderLine,
  baseTransferOrderLine,
} from "../testing/fixtures";
import { run } from "./closeTransferOrder";

describe("closeTransferOrder", () => {
  const ctx: CommandContext = {
    actorId: "test-actor",
    permissions: ["inventory:transferOrder:closeTransferOrder"],
  };

  it("closes an OPEN transfer order when in-transit quantity is zero", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults(
      [baseOpenTransferOrder], // TransferOrder select
      [
        {
          ...baseTransferOrderLine,
          orderedQuantity: "10",
          shippedQuantity: "4",
          receivedQuantity: "4",
        },
      ], // TransferOrderLine select
      [], // StockReservation update
      [], // InventorySupplyPlan update
      [{ ...baseOpenTransferOrder, status: "CLOSED" }], // TransferOrder update
    );

    const result = await mock.withTx((trx) => run(trx, { id: "transfer-order-3" }, ctx));
    const value = expectOk<{
      transferOrder: { status: string };
      stockReservations: unknown[];
      supplyPlans: unknown[];
    }>(result as never);

    expect(value.transferOrder.status).toBe("CLOSED");
    expect(mock.updates[0].updateValues()).toEqual({ status: "CLOSED" });
    expect(mock.updates[1].updateValues()).toEqual({ status: "CLOSED" });
    expect(mock.updates[2].updateValues()).toEqual(expect.objectContaining({ status: "CLOSED" }));
  });

  it("closes a DRAFT transfer order without planning rows", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults(
      [baseDraftTransferOrder], // TransferOrder select
      [baseTransferOrderLine], // TransferOrderLine select
      [], // StockReservation update
      [], // InventorySupplyPlan update
      [{ ...baseDraftTransferOrder, status: "CLOSED" }], // TransferOrder update
    );

    const result = await mock.withTx((trx) => run(trx, { id: "transfer-order-1" }, ctx));
    const value = expectOk<{ transferOrder: { status: string } }>(result as never);

    expect(value.transferOrder.status).toBe("CLOSED");
  });

  it("returns error when in-transit quantity remains", async () => {
    const mock = createKyselyMock<Namespace["main-db"]>();
    mock.enqueueResults([baseOpenTransferOrder], [partiallyReceivedTransferOrderLine]);

    const result = await mock.withTx((trx) => run(trx, { id: "transfer-order-3" }, ctx));

    expectErr(result as never, TransferOrderInTransitError);
    expect(mock.updates).toHaveLength(0);
  });
});
