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

export interface RecordCountLineInput {
  inventoryCountId: string;
  countLineId: string;
  countedQuantity: number;
}

/**
 * Function: recordCountLine
 *
 * Records the physically counted quantity for a specific count line.
 * Variance is automatically calculated as countedQuantity minus system snapshot quantity.
 */
export async function run(db: Transaction, input: RecordCountLineInput, _ctx: CommandContext) {
  const { inventoryCountId, countLineId, countedQuantity } = 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 count is IN_PROGRESS
  if (count.status !== "IN_PROGRESS") {
    return err(new CountNotInProgressError(inventoryCountId));
  }

  // 3. Fetch count line
  const countLine = await db
    .selectFrom("InventoryCountLine")
    .selectAll()
    .where("id", "=", countLineId)
    .where("inventoryCountId", "=", inventoryCountId)
    .forUpdate()
    .executeTakeFirst();

  if (!countLine) {
    return err(new CountLineNotFoundError(countLineId));
  }

  // 4. Validate line status
  if (
    countLine.status !== "PENDING" &&
    countLine.status !== "RECOUNT" &&
    countLine.status !== "REJECTED"
  ) {
    return err(new CountLineInvalidStatusError(countLineId));
  }

  // 5. Calculate variance
  const variance = countedQuantity - countLine.systemQuantity;

  // 6. Update count line
  const updatedLine = await db
    .updateTable("InventoryCountLine")
    .set({
      countedQuantity,
      variance,
      status: "PENDING",
      updatedAt: new Date(),
    })
    .where("id", "=", countLineId)
    .returningAll()
    .executeTakeFirst();

  return ok({ countLine: updatedLine! });
}
