import { describe, expect, it } from "vitest";
import { createMockDb } from "../../../testing/index";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  CountNotFoundError,
  CountNotInProgressError,
  UnresolvedCountLinesError,
} from "../lib/errors.generated";
import {
  baseInProgressCount,
  basePlannedCount,
  basePendingCountLine,
  baseApprovedCountLine,
} from "../testing/fixtures";
import { run } from "./completeInventoryCount";
import type { CommandContext } from "@tailor-platform/erp-kit/module";

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

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

    const result = await run(db, { inventoryCountId: "nonexistent" }, ctx);
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(CountNotFoundError);
    }
  });

  it("returns error when not in progress", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select.mockReturnValueOnce(basePlannedCount); // PLANNED status

    const result = await run(db, { inventoryCountId: "count-1" }, ctx);
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(CountNotInProgressError);
    }
  });

  it("returns error when unresolved lines exist", async () => {
    const { db, spies } = createMockDb<Transaction>();
    spies.select
      .mockReturnValueOnce(baseInProgressCount) // count lookup
      .mockReturnValueOnce([basePendingCountLine, baseApprovedCountLine]); // lines: one PENDING

    const result = await run(db, { inventoryCountId: "count-2" }, ctx);
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(result.error).toBeInstanceOf(UnresolvedCountLinesError);
    }
  });

  it("completes count", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const allResolvedLines = [
      baseApprovedCountLine,
      { ...basePendingCountLine, status: "REJECTED" },
    ];
    const completedCount = { ...baseInProgressCount, status: "COMPLETED", isFrozen: false };

    spies.select
      .mockReturnValueOnce(baseInProgressCount) // count lookup
      .mockReturnValueOnce(allResolvedLines); // all lines resolved
    spies.update.mockReturnValue(completedCount);

    const result = await run(db, { inventoryCountId: "count-2" }, ctx);
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.inventoryCount.status).toBe("COMPLETED");
    }
    expect(spies.update).toHaveBeenCalled();
  });

  it("unfreezes stock after completion", async () => {
    const { db, spies } = createMockDb<Transaction>();
    const frozenCount = { ...baseInProgressCount, isFrozen: true };
    const completedCount = { ...frozenCount, status: "COMPLETED", isFrozen: false };

    spies.select
      .mockReturnValueOnce(frozenCount) // count lookup, isFrozen: true
      .mockReturnValueOnce([baseApprovedCountLine]); // all lines resolved
    spies.update.mockReturnValue(completedCount);

    const result = await run(db, { inventoryCountId: "count-2" }, ctx);
    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.inventoryCount.isFrozen).toBe(false);
    }
    expect(spies.set).toHaveBeenCalledWith(
      expect.objectContaining({ isFrozen: false, status: "COMPLETED" }),
    );
  });
});
