import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/core";
import { accountPayableDocumentLifecycle } from "../db/accountPayableDocument.lifecycle.generated";
import type { Transaction } from "../generated/kysely-tailordb";
import { syncPurchaseOrderBillingStatusFromAccountPayable } from "../internal/purchaseBillingFeedback";
import { ApDocumentNotFoundError, ApInvalidDocumentStatusError } from "../lib/errors.generated";
import type { PurchaseCommands } from "../module";

export interface CancelAccountPayableDocumentInput {
  id: string;
}

export async function run(
  db: Transaction,
  input: CancelAccountPayableDocumentInput,
  ctx: CommandContext,
  purchaseCommands: Pick<PurchaseCommands, "recalculatePurchaseOrderBillingStatus">,
) {
  const document = await db
    .selectFrom("AccountPayableDocument")
    .selectAll()
    .where("id", "=", input.id)
    .forUpdate()
    .executeTakeFirst();

  if (!document) return err(new ApDocumentNotFoundError(input.id));

  const operation = document.status === "DRAFT" ? "cancelDraft" : "cancelRegistered";
  const nextStatus = accountPayableDocumentLifecycle.tryTransition(document.status, operation);
  if (!nextStatus) return err(new ApInvalidDocumentStatusError(input.id));

  const cancelledDocument = await db
    .updateTable("AccountPayableDocument")
    .set({
      status: nextStatus,
      cancelledAt: new Date(),
    })
    .where("id", "=", input.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  if (document.status === "REGISTERED") {
    const lines = await db
      .selectFrom("AccountPayableDocumentLine")
      .selectAll()
      .where("accountPayableDocumentId", "=", input.id)
      .execute();
    const billingSyncResult = await syncPurchaseOrderBillingStatusFromAccountPayable(
      db,
      { document: cancelledDocument, lines },
      ctx,
      purchaseCommands,
    );
    if (!billingSyncResult.ok) return billingSyncResult;
  }

  return ok({ accountPayableDocument: cancelledDocument });
}
