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

const EXECUTABLE_ORDER_STATUSES = ["RELEASED", "IN_PROGRESS"] as const;

export interface StartWorkOrderInput {
  id: string;
}

/**
 * Function: startWorkOrder
 *
 * Begins execution on a pending work order. Records the actual start timestamp,
 * moves the work order to IN_PROGRESS, and transitions the parent production
 * order to IN_PROGRESS if it was RELEASED.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: StartWorkOrderInput & CF,
  _ctx: CommandContext,
) {
  const { id, ...customFields } = input;
  void customFields;

  // 1. Fetch work order with lock
  const workOrder = await db
    .selectFrom("WorkOrder")
    .selectAll()
    .where("id", "=", id)
    .forUpdate()
    .executeTakeFirst();

  if (!workOrder) {
    return err(new WorkOrderNotFoundError(id));
  }

  // 2. Validate status is PENDING
  if (workOrder.status !== "PENDING") {
    return err(new WorkOrderNotStartableError(id));
  }

  // 3. Check parent production order is in an execution-capable state
  const parentOrder = await db
    .selectFrom("ProductionOrder")
    .selectAll()
    .where("id", "=", workOrder.productionOrderId)
    .forUpdate()
    .executeTakeFirst();

  if (
    !parentOrder ||
    !EXECUTABLE_ORDER_STATUSES.includes(
      parentOrder.status as (typeof EXECUTABLE_ORDER_STATUSES)[number],
    )
  ) {
    return err(new ParentOrderNotExecutableError(id));
  }

  // 4. Check preceding operations are complete (sequence order guard)
  const siblingWorkOrders = await db
    .selectFrom("WorkOrder")
    .selectAll()
    .where("productionOrderId", "=", workOrder.productionOrderId)
    .execute();

  const hasPendingPredecessor = siblingWorkOrders.some(
    (wo) =>
      wo.routingOperationSequenceNumber < workOrder.routingOperationSequenceNumber &&
      wo.status !== "COMPLETE" &&
      wo.status !== "CANCELLED",
  );

  if (hasPendingPredecessor) {
    return err(new OperationSequenceBlockedError(id));
  }

  // 5. Record actual start and set IN_PROGRESS
  const now = new Date();

  const updatedWorkOrder = await db
    .updateTable("WorkOrder")
    .set({
      status: "IN_PROGRESS",
      actualStartDate: now,
      updatedAt: now,
    })
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirstOrThrow();

  // 6. Create STARTED execution event
  await db
    .insertInto("WorkOrderExecutionEvent")
    .values({
      workOrderId: id,
      eventType: "STARTED",
      timestamp: now,
      quantity: null,
      timeValue: null,
      scrapValue: null,
      notes: null,
      createdAt: now,
      updatedAt: null,
    })
    .execute();

  // 7. If parent production order is RELEASED, transition to IN_PROGRESS
  if (parentOrder.status === "RELEASED") {
    await db
      .updateTable("ProductionOrder")
      .set({
        status: "IN_PROGRESS",
        updatedAt: now,
      })
      .where("id", "=", parentOrder.id)
      .execute();
  }

  return ok({ workOrder: updatedWorkOrder });
}
