import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  InvalidReservationQuantitiesError,
  StockReservationNotFoundError,
  StockReservationNotOpenError,
} from "../lib/errors.generated";
import { expectOk } from "../testing/commandTestUtils";
import { baseStockReservation } from "../testing/fixtures";
import {
  consumeStockReservationInternal,
  getOpenStockReservationQuantity,
  sumOpenStockReservationQuantity,
} from "./stockReservation";

describe("stockReservation internal helpers", () => {
  it("calculates open reservation quantity", () => {
    expect(
      getOpenStockReservationQuantity({
        reservedQuantity: "10",
        consumedQuantity: "4",
      }).toString(),
    ).toBe("6");
    expect(
      getOpenStockReservationQuantity({
        reservedQuantity: "4",
        consumedQuantity: "10",
      }).toString(),
    ).toBe("0");
  });

  it("sums open reservation quantity", () => {
    expect(
      sumOpenStockReservationQuantity([
        { reservedQuantity: "10", consumedQuantity: "4" },
        { reservedQuantity: "3", consumedQuantity: "0" },
      ]).toString(),
    ).toBe("9");
  });

  it("consumes reservation internally", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const updatedReservation = { ...baseStockReservation, consumedQuantity: "4", status: "OPEN" };
    spies.select.mockReturnValueOnce(baseStockReservation);
    spies.update.mockReturnValueOnce(updatedReservation);

    const result = await consumeStockReservationInternal(db, {
      id: "stock-reservation-1",
      consumedQuantity: "4",
    });
    const { stockReservation } = expectOk<{
      stockReservation: { consumedQuantity: string; status: string };
    }>(result as never);

    expect(stockReservation.consumedQuantity).toBe("4");
    expect(stockReservation.status).toBe("OPEN");
  });

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

    const result = await consumeStockReservationInternal(db, {
      id: "stock-reservation-1",
      consumedQuantity: "4",
    });

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(StockReservationNotFoundError);
    }
  });

  it("returns error when consumed quantity is invalid", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await consumeStockReservationInternal(db, {
      id: "stock-reservation-1",
      consumedQuantity: "0",
    });

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InvalidReservationQuantitiesError);
    }
  });

  it("returns error when reservation is not open", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce({ ...baseStockReservation, status: "CLOSED" });

    const result = await consumeStockReservationInternal(db, {
      id: "stock-reservation-1",
      consumedQuantity: "4",
    });

    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(StockReservationNotOpenError);
    }
  });
});
