import type { Transaction } from "../generated/kysely-tailordb";
import { CoNotDraftError, CoNotFoundError } 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 UpdatePurchaseChangeOrderInput {
  id: string;
  reason?: string;
  lines?: ChangeOrderLineInput[];
}

export async function run(
  db: Transaction,
  input: UpdatePurchaseChangeOrderInput,
  ctx: CommandContext,
) {
  void ctx;
  const changeOrder = await db
    .selectFrom("PurchaseChangeOrder")
    .selectAll()
    .where("id", "=", input.id)
    .forUpdate()
    .executeTakeFirst();
  if (!changeOrder) {
    return err(new CoNotFoundError(input.id));
  }
  if (changeOrder.changeOrderStatus !== "DRAFT") {
    return err(new CoNotDraftError(input.id));
  }

  const updates: Record<string, unknown> = { updatedAt: new Date() };
  if (input.reason !== undefined) {
    updates.reason = input.reason;
  }

  const updated = await db
    .updateTable("PurchaseChangeOrder")
    .set(updates)
    .where("id", "=", input.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  if (input.lines !== undefined) {
    // Delete old lines
    await db
      .deleteFrom("PurchaseChangeOrderLine")
      .where("purchaseChangeOrderId", "=", input.id)
      .execute();

    // Insert new lines
    if (input.lines.length > 0) {
      await db
        .insertInto("PurchaseChangeOrderLine")
        .values(
          input.lines.map((line) => ({
            purchaseChangeOrderId: input.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: updated });
}
