import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core";
import { productionOrderLifecycle } from "../db/productionOrder.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  ProductionOrderNotFoundError,
  ProductionOrderNotCancellableError,
  ExecutionAlreadyStartedError,
  InventoryHandoffExistsError,
} from "../lib/errors.generated";

export interface CancelProductionOrderInput {
  id: string;
}

/**
 * Function: cancelProductionOrder
 *
 * Abandons a draft or not-yet-started released order. Preserves audit
 * history while blocking further execution updates and cascading
 * cancellation to pending work orders.
 */
export async function run(
  db: Transaction,
  input: CancelProductionOrderInput,
  _ctx: CommandContext,
) {
  const { id } = input;

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

  if (!order) {
    return err(new ProductionOrderNotFoundError(id));
  }

  // 2. Validate status is cancellable
  const nextStatus = productionOrderLifecycle.tryTransition(order.status, "cancel");
  if (!nextStatus) {
    return err(new ProductionOrderNotCancellableError(id));
  }

  // 3. For released orders, check execution and inventory evidence
  if (order.status === "RELEASED") {
    // Check work orders for execution evidence
    const workOrders = await db
      .selectFrom("WorkOrder")
      .selectAll()
      .where("productionOrderId", "=", id)
      .execute();

    const hasExecution = workOrders.some(
      (wo) =>
        wo.status === "IN_PROGRESS" ||
        wo.status === "PAUSED" ||
        wo.status === "COMPLETE" ||
        wo.completedQuantity > 0 ||
        wo.actualStartDate != null,
    );

    if (hasExecution) {
      return err(new ExecutionAlreadyStartedError(id));
    }

    // Check for inventory handoff evidence
    const costSummary = await db
      .selectFrom("ManufacturingCostSummary")
      .selectAll()
      .where("productionOrderId", "=", id)
      .executeTakeFirst();

    if (
      costSummary &&
      (costSummary.actualMaterialCost > 0 ||
        costSummary.actualLaborCost > 0 ||
        costSummary.actualMachineCost > 0 ||
        costSummary.actualOverheadCost > 0)
    ) {
      return err(new InventoryHandoffExistsError(id));
    }

    // 4. Cascade cancellation to pending work orders
    await db
      .updateTable("WorkOrder")
      .set({
        status: "CANCELLED",
      })
      .where("productionOrderId", "=", id)
      .where("status", "=", "PENDING")
      .execute();
  }

  // 5. Set order status to CANCELLED
  const cancelledOrder = await db
    .updateTable("ProductionOrder")
    .set({
      status: nextStatus,
    })
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ productionOrder: cancelledOrder });
}
