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,
  ProductionOrderNotReopenableError,
  ReopenReasonRequiredError,
  CostSummaryNotReopenableError,
  OrderAlreadyClosedError,
} from "../lib/errors.generated";

export interface ReopenProductionOrderInput {
  id: string;
  reason: string;
}

/**
 * Function: reopenProductionOrder
 *
 * Re-enables execution after a technically complete order needs more
 * shop-floor work. It reverses the execution freeze and returns the linked
 * cost summary to active collection.
 */
export async function run(
  db: Transaction,
  input: ReopenProductionOrderInput,
  _ctx: CommandContext,
) {
  const { id, reason } = 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. Check if order is already closed
  if (order.status === "CLOSED") {
    return err(new OrderAlreadyClosedError(id));
  }

  // 3. Validate status is reopenable
  const nextStatus = productionOrderLifecycle.tryTransition(order.status, "reopen");
  if (!nextStatus) {
    return err(new ProductionOrderNotReopenableError(id));
  }

  // 4. Validate reopen reason
  if (!reason || reason.trim() === "") {
    return err(new ReopenReasonRequiredError(id));
  }

  // 5. Find and validate cost summary
  const costSummary = await db
    .selectFrom("ManufacturingCostSummary")
    .selectAll()
    .where("productionOrderId", "=", id)
    .forUpdate()
    .executeTakeFirst();

  if (
    !costSummary ||
    (costSummary.status !== "PENDING_VARIANCE_REVIEW" && costSummary.status !== "VARIANCE_REVIEWED")
  ) {
    return err(new CostSummaryNotReopenableError(id));
  }

  // 6. Return cost summary to COLLECTING
  await db
    .updateTable("ManufacturingCostSummary")
    .set({
      status: "COLLECTING",
    })
    .where("id", "=", costSummary.id)
    .execute();

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

  return ok({ productionOrder: reopenedOrder });
}
