import type { Transaction } from "../generated/kysely-tailordb";
import {
  OpenChangeOrderExistsError,
  PoNotFoundError,
  PoNotOrderedError,
} from "../lib/errors.generated";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";

export interface ChangeOrderLineInput {
  action: "ADD" | "MODIFY" | "REMOVE";
  originalPurchaseOrderLineId?: string | null;
  itemId?: string | null;
  quantity?: string | null;
  unitPrice?: string | null;
  unitId?: string | null;
  receivingSiteId?: string | null;
}

export interface CreatePurchaseChangeOrderInput {
  purchaseOrderId: string;
  reason: string;
  lines: ChangeOrderLineInput[];
}

export async function run(
  db: Transaction,
  input: CreatePurchaseChangeOrderInput,
  ctx: CommandContext,
) {
  void ctx;
  const purchaseOrder = await db
    .selectFrom("PurchaseOrder")
    .selectAll()
    .where("id", "=", input.purchaseOrderId)
    .forUpdate()
    .executeTakeFirst();
  if (!purchaseOrder) {
    return err(new PoNotFoundError(input.purchaseOrderId));
  }
  if (purchaseOrder.orderStatus !== "ORDERED") {
    return err(new PoNotOrderedError(input.purchaseOrderId));
  }

  // Check no open change order exists
  const openCo = await db
    .selectFrom("PurchaseChangeOrder")
    .selectAll()
    .where("purchaseOrderId", "=", input.purchaseOrderId)
    .where("changeOrderStatus", "in", ["DRAFT", "SUBMITTED", "APPROVED"])
    .executeTakeFirst();
  if (openCo) {
    return err(new OpenChangeOrderExistsError(input.purchaseOrderId));
  }

  const fromRevisionNumber = purchaseOrder.currentRevisionNumber ?? 1;

  const changeOrder = await db
    .insertInto("PurchaseChangeOrder")
    .values({
      purchaseOrderId: input.purchaseOrderId,
      fromRevisionNumber,
      reason: input.reason,
      changeOrderStatus: "DRAFT",
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirstOrThrow();

  if (input.lines.length > 0) {
    await db
      .insertInto("PurchaseChangeOrderLine")
      .values(
        input.lines.map((line) => ({
          purchaseChangeOrderId: changeOrder.id,
          action: line.action,
          originalPurchaseOrderLineId: line.originalPurchaseOrderLineId ?? null,
          itemId: line.itemId ?? null,
          quantity: line.quantity ?? null,
          unitPrice: line.unitPrice ?? null,
          unitId: line.unitId ?? null,
          receivingSiteId: line.receivingSiteId ?? null,
          createdAt: new Date(),
          updatedAt: null,
        })),
      )
      .execute();
  }

  return ok({ changeOrder });
}
