import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { DB } from "../generated/kysely-tailordb";
import { baseActiveLot, baseMoveLine } from "../testing/fixtures";
import { expectOk, expectErr } from "../testing/commandTestUtils";
import { LotNotFoundError } from "../lib/errors.generated";
import { run } from "./traceLotBackward";

const receiptMoveLine = {
  ...baseMoveLine,
  lotId: "lot-1",
  movementType: "GOODS_RECEIPT",
  executedAt: new Date("2024-01-02T00:00:00.000Z"),
  status: "DONE",
  reasonCode: null,
};

describe("traceLotBackward", () => {
  it("returns inbound movements for lot", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(baseActiveLot);
    spies.select.mockReturnValueOnce([receiptMoveLine]);

    const result = await run(db, { lotId: "lot-1" });
    const { moveLines } = expectOk<{ moveLines: unknown[] }>(result as never);

    expect(moveLines).toHaveLength(1);
  });

  it("includes movement date and source reference", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(baseActiveLot);
    spies.select.mockReturnValueOnce([receiptMoveLine]);

    const result = await run(db, { lotId: "lot-1" });
    const { moveLines } = expectOk<{
      moveLines: { executedAt: Date; reasonCode: string | null }[];
    }>(result as never);

    expect(moveLines[0].executedAt).toEqual(new Date("2024-01-02T00:00:00.000Z"));
    expect(moveLines[0].reasonCode).toBeNull();
  });

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

    const result = await run(db, { lotId: "non-existent" });

    expectErr(result as never, LotNotFoundError);
  });

  it("returns empty list when no receipt found", async () => {
    const { db, spies } = createMockDb<DB>();
    spies.select.mockReturnValueOnce(baseActiveLot);
    spies.select.mockReturnValueOnce([]);

    const result = await run(db, { lotId: "lot-1" });
    const { moveLines } = expectOk<{ moveLines: unknown[] }>(result as never);

    expect(moveLines).toEqual([]);
  });
});
