import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import { StockLevelNotFoundError, InsufficientReservedStockError } from "../lib/errors.generated";
import { baseStockLevel } from "../testing/fixtures";
import { run } from "./releaseReservation";
import type { CommandContext } from "@tailor-platform/erp-kit/module";

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

  it("returns error when stock level not found", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(undefined); // StockLevel lookup

    const result = await run(
      db,
      { itemId: "item-1", storageLocationId: "location-1", quantity: 5 },
      ctx,
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(StockLevelNotFoundError);
    }
  });

  it("returns error when release exceeds reserved", async () => {
    const { db, spies } = createMockDb<Transaction>();
    // baseStockLevel: reserved=10
    spies.select.mockReturnValueOnce(baseStockLevel); // StockLevel found

    const result = await run(
      db,
      { itemId: "item-1", storageLocationId: "location-1", quantity: 15 },
      ctx,
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InsufficientReservedStockError);
    }
  });

  it("releases reservation successfully", async () => {
    const { db, spies } = createMockDb<Transaction>();
    // baseStockLevel: reserved=10
    const updatedStockLevel = { ...baseStockLevel, reserved: 5, updatedAt: new Date() };

    spies.select.mockReturnValueOnce(baseStockLevel); // StockLevel found
    spies.update.mockReturnValue(updatedStockLevel);

    const result = await run(
      db,
      { itemId: "item-1", storageLocationId: "location-1", quantity: 5 },
      ctx,
    );
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.stockLevel.reserved).toBe(5);
    }
    expect(spies.update).toHaveBeenCalled();
  });
});
