import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  InvalidCountTypeError,
  WarehouseNotFoundError,
  StorageLocationNotFoundError,
} from "../lib/errors.generated";
import { baseActiveWarehouse, baseZone } from "../testing/fixtures";
import { run } from "./createInventoryCount";
import type { CommandContext } from "@tailor-platform/erp-kit/module";

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

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

    const result = await run(
      db,
      {
        countType: "FULL",
        warehouseId: "nonexistent",
        plannedDate: new Date("2024-02-01"),
      },
      ctx,
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(WarehouseNotFoundError);
    }
  });

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

    const result = await run(
      db,
      {
        countType: "INVALID",
        warehouseId: "warehouse-1",
        plannedDate: new Date("2024-02-01"),
      },
      ctx,
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(InvalidCountTypeError);
    }
  });

  it("creates full count", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseActiveWarehouse); // warehouse exists
    const createdCount = {
      id: "count-new",
      countType: "FULL",
      warehouseId: "warehouse-1",
      storageLocationId: null,
      plannedDate: new Date("2024-02-01"),
      status: "PLANNED",
      isFrozen: false,
      createdAt: new Date(),
      updatedAt: null,
    };
    spies.insert.mockReturnValue(createdCount);

    const result = await run(
      db,
      {
        countType: "FULL",
        warehouseId: "warehouse-1",
        plannedDate: new Date("2024-02-01"),
      },
      ctx,
    );
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.inventoryCount.status).toBe("PLANNED");
      expect(result.value.inventoryCount.countType).toBe("FULL");
    }
    expect(spies.insert).toHaveBeenCalled();
  });

  it("creates cycle count for specific location", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(baseZone); // location exists
    const createdCount = {
      id: "count-new",
      countType: "CYCLE",
      warehouseId: null,
      storageLocationId: "location-1",
      plannedDate: new Date("2024-02-01"),
      status: "PLANNED",
      isFrozen: false,
      createdAt: new Date(),
      updatedAt: null,
    };
    spies.insert.mockReturnValue(createdCount);

    const result = await run(
      db,
      {
        countType: "CYCLE",
        storageLocationId: "location-1",
        plannedDate: new Date("2024-02-01"),
      },
      ctx,
    );
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.inventoryCount.countType).toBe("CYCLE");
      expect(result.value.inventoryCount.storageLocationId).toBe("location-1");
    }
    expect(spies.insert).toHaveBeenCalled();
  });

  it("returns error when no location scope provided", async () => {
    const { db } = createMockDb<Transaction>();

    const result = await run(
      db,
      {
        countType: "FULL",
        plannedDate: new Date("2024-02-01"),
      },
      ctx,
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(WarehouseNotFoundError);
    }
  });

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

    const result = await run(
      db,
      {
        countType: "CYCLE",
        storageLocationId: "nonexistent",
        plannedDate: new Date("2024-02-01"),
      },
      ctx,
    );
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(StorageLocationNotFoundError);
    }
  });
});
