import type { Transaction } from "../generated/kysely-tailordb";
import { CountNotFoundError, CountNotPlannedError } from "../lib/errors.generated";
import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface StartInventoryCountInput {
  inventoryCountId: string;
  freeze?: boolean;
}

/**
 * Function: startInventoryCount
 *
 * Initiates the count process, transitioning from PLANNED to IN_PROGRESS.
 * Snapshots current on-hand quantities and creates count lines.
 */
export async function run(db: Transaction, input: StartInventoryCountInput, _ctx: CommandContext) {
  const { inventoryCountId, freeze = false } = input;

  // 1. Fetch count
  const count = await db
    .selectFrom("InventoryCount")
    .selectAll()
    .where("id", "=", inventoryCountId)
    .forUpdate()
    .executeTakeFirst();

  if (!count) {
    return err(new CountNotFoundError(inventoryCountId));
  }

  // 2. Validate status
  if (count.status !== "PLANNED") {
    return err(new CountNotPlannedError(inventoryCountId));
  }

  // 3. Snapshot system quantities — get stock levels in scope
  let stockLevelsQuery = db.selectFrom("StockLevel").selectAll();

  if (count.warehouseId) {
    // Get all locations for this warehouse, then get stock levels
    const locations = await db
      .selectFrom("StorageLocation")
      .selectAll()
      .where("warehouseId", "=", count.warehouseId)
      .execute();

    const locationIds = locations.map((l) => l.id);

    if (locationIds.length > 0) {
      stockLevelsQuery = stockLevelsQuery.where("storageLocationId", "in", locationIds);
    }
  } else if (count.storageLocationId) {
    stockLevelsQuery = stockLevelsQuery.where("storageLocationId", "=", count.storageLocationId);
  }

  const stockLevels = await stockLevelsQuery.execute();

  // 4. Create count lines for each item-location pair
  for (const sl of stockLevels) {
    await db
      .insertInto("InventoryCountLine")
      .values({
        inventoryCountId,
        itemId: sl.itemId,
        storageLocationId: sl.storageLocationId,
        systemQuantity: sl.onHand,
        countedQuantity: null,
        variance: null,
        status: "PENDING",
        createdAt: new Date(),
        updatedAt: null,
      })
      .returningAll()
      .executeTakeFirst();
  }

  // 5. Update count status to IN_PROGRESS and optionally freeze
  const updatedCount = await db
    .updateTable("InventoryCount")
    .set({
      status: "IN_PROGRESS",
      isFrozen: freeze,
      updatedAt: new Date(),
    })
    .where("id", "=", inventoryCountId)
    .returningAll()
    .executeTakeFirst();

  return ok({ inventoryCount: updatedCount! });
}
