/* eslint-disable @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
import type { Transaction } from "../generated/kysely-tailordb";
import {
  ItemNotActiveError,
  MissingCommercialSnapshotError,
  PartnerNotSupplierError,
  PurchaseOrderNotFoundError,
  PurchaseOrderNotSubmittedError,
  SupplierNotActiveError,
} from "../lib/errors.generated";
import {
  buildPaymentTermSnapshot,
  decodeJson,
  encodeJson,
  getSupplierRole,
  isActiveStatus,
  selectOne,
  type PurchaseOrderLineInput,
} from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface ApprovePurchaseOrderInput {
  id: string;
}

export async function run(db: Transaction, input: ApprovePurchaseOrderInput, ctx: CommandContext) {
  void ctx;
  const purchaseOrder = await selectOne(db, "PurchaseOrder", "id", input.id, true);
  if (!purchaseOrder) {
    return err(new PurchaseOrderNotFoundError(input.id));
  }
  if (purchaseOrder.status !== "SUBMITTED") {
    return err(new PurchaseOrderNotSubmittedError(input.id));
  }

  const supplier = await selectOne(db, "BusinessPartner", "id", purchaseOrder.supplierId as string);
  if (!supplier || !isActiveStatus(supplier.status as string | null)) {
    return err(new SupplierNotActiveError(purchaseOrder.supplierId as string));
  }
  if (!(await getSupplierRole(db, purchaseOrder.supplierId as string))) {
    return err(new PartnerNotSupplierError(purchaseOrder.supplierId as string));
  }

  let paymentTermSnapshot = purchaseOrder.paymentTermSnapshot as string | null;
  if (!paymentTermSnapshot && purchaseOrder.paymentTermId) {
    const paymentTerm = await selectOne(
      db,
      "PurchasePaymentTerm",
      "id",
      purchaseOrder.paymentTermId as string,
    );
    if (!paymentTerm) {
      return err(new MissingCommercialSnapshotError(input.id));
    }
    paymentTermSnapshot = encodeJson(buildPaymentTermSnapshot(paymentTerm));
  }
  if (!paymentTermSnapshot && purchaseOrder.paymentTermId) {
    return err(new MissingCommercialSnapshotError(input.id));
  }

  const lines = decodeJson<PurchaseOrderLineInput[]>(purchaseOrder.lines, []).map((line) => ({
    ...line,
    priceSnapshot: line.priceSnapshot ?? {
      unitPrice: line.unitPrice,
      matchedPriceRuleId: line.matchedPriceRuleId ?? null,
    },
  }));

  for (const line of lines) {
    const item = await selectOne(db, "Item", "id", line.itemId);
    if (!item || !isActiveStatus(item.status as string | null)) {
      return err(new ItemNotActiveError(line.itemId));
    }
  }

  const approved = await db
    .updateTable("PurchaseOrder")
    .set({
      status: "ORDERED",
      lines: encodeJson(lines),
      paymentTermSnapshot,
      updatedAt: new Date(),
    })
    .where("id", "=", input.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ purchaseOrder: approved });
}
