import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import { purchaseOrderLifecycle } from "../db/purchaseOrder.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  EmptyPurchaseOrderLinesError,
  PartnerNotSupplierError,
  PurchaseOrderNotDraftError,
  PurchaseOrderNotFoundError,
} from "../lib/errors.generated";
import type { BusinessPartnerQueries } from "../module";

export interface SubmitPurchaseOrderInput {
  id: string;
}

export async function run(
  db: Transaction,
  input: SubmitPurchaseOrderInput,
  ctx: CommandContext,
  businessPartnerQueries: Pick<BusinessPartnerQueries, "getPartnerRole">,
) {
  const purchaseOrder = await db
    .selectFrom("PurchaseOrder")
    .selectAll()
    .where("id", "=", input.id)
    .forUpdate()
    .executeTakeFirst();
  if (!purchaseOrder) {
    return err(new PurchaseOrderNotFoundError(input.id));
  }
  const nextOrderStatus = purchaseOrderLifecycle.tryTransition(purchaseOrder.orderStatus, "submit");
  if (!nextOrderStatus) {
    return err(new PurchaseOrderNotDraftError(input.id));
  }

  const lines = await db
    .selectFrom("PurchaseOrderLine")
    .selectAll()
    .where("purchaseOrderId", "=", input.id)
    .execute();

  if (lines.length === 0) {
    return err(new EmptyPurchaseOrderLinesError(input.id));
  }
  const { partnerRole } = (
    await businessPartnerQueries.getPartnerRole(
      db,
      { partnerId: purchaseOrder.supplierId, role: "SUPPLIER" },
      ctx,
    )
  ).value;
  if (!partnerRole) {
    return err(new PartnerNotSupplierError(purchaseOrder.supplierId));
  }

  const submitted = await db
    .updateTable("PurchaseOrder")
    .set({ orderStatus: nextOrderStatus })
    .where("id", "=", input.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ purchaseOrder: submitted });
}
