import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { DB } from "../generated/kysely-tailordb";
import { baseStockLevel, emptyStockLevel } from "../testing/fixtures";
import { expectOk } from "../testing/commandTestUtils";
import { run } from "./getStockLevel";

describe("getStockLevel", () => {
  it("returns stock level when found", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(baseStockLevel);

    const result = await run(db, {
      itemId: "item-1",
      storageLocationId: "location-1",
    });
    const { stockLevel } = expectOk<{ stockLevel: unknown }>(result as never);

    expect(stockLevel).not.toBeNull();
    expect(stockLevel).toMatchObject({
      itemId: "item-1",
      storageLocationId: "location-1",
    });
  });

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

    const result = await run(db, {
      itemId: "non-existent",
      storageLocationId: "location-1",
    });
    const { stockLevel } = expectOk<{ stockLevel: null }>(result as never);

    expect(stockLevel).toBeNull();
  });

  it("correctly computes available quantity", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(baseStockLevel);

    const result = await run(db, {
      itemId: "item-1",
      storageLocationId: "location-1",
    });
    const { stockLevel } = expectOk<{
      stockLevel: { availableQuantity: number };
    }>(result as never);

    // onHand(100) - reserved(10) - blocked(5) = 85
    expect(stockLevel.availableQuantity).toBe(85);
  });

  it("available equals onHand minus reserved minus blocked", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(emptyStockLevel);

    const result = await run(db, {
      itemId: "item-2",
      storageLocationId: "location-1",
    });
    const { stockLevel } = expectOk<{
      stockLevel: { availableQuantity: number };
    }>(result as never);

    // onHand(0) - reserved(0) - blocked(0) = 0
    expect(stockLevel.availableQuantity).toBe(0);
  });
});
