import { ok, type ReadonlyDB } from "@tailor-platform/erp-kit/core";
import { Decimal } from "decimal.js";
import type { DB } from "../generated/kysely-tailordb";

export type GetPurchaseOrderInput =
  | { id: string }
  | { companyId: string; externalSupplierOrderReference: string };

export async function run(db: ReadonlyDB<DB>, input: GetPurchaseOrderInput) {
  let id: string;
  if ("id" in input) {
    id = input.id;
  } else {
    const purchaseOrder = await db
      .selectFrom("PurchaseOrder")
      .selectAll()
      .where("companyId", "=", input.companyId)
      .where("externalSupplierOrderReference", "=", input.externalSupplierOrderReference)
      .executeTakeFirst();
    if (!purchaseOrder) return ok({ purchaseOrder: null });
    id = purchaseOrder.id;
  }

  const purchaseOrder = await db
    .selectFrom("PurchaseOrder")
    .selectAll()
    .where("id", "=", id)
    .executeTakeFirst();
  if (!purchaseOrder) return ok({ purchaseOrder: null });

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

  const lineIds = lines.map((l) => l.id);

  // Fetch fulfillment data only when there are lines
  const [billLines, matchedBills] =
    lineIds.length > 0
      ? await Promise.all([
          db
            .selectFrom("PurchaseBillLine")
            .selectAll()
            .where("purchaseOrderLineId", "in", lineIds)
            .execute(),
          db.selectFrom("PurchaseBill").selectAll().where("status", "=", "MATCHED").execute(),
        ])
      : [[], []];

  const matchedBillIdSet = new Set(matchedBills.map((b) => b.id));

  // Billed quantity per PO line ID (from MATCHED bills only)
  const billedByLineId = new Map<string, Decimal>();
  for (const bl of billLines) {
    if (bl.purchaseOrderLineId && matchedBillIdSet.has(bl.purchaseBillId)) {
      billedByLineId.set(
        bl.purchaseOrderLineId,
        (billedByLineId.get(bl.purchaseOrderLineId) ?? new Decimal(0)).plus(bl.quantity),
      );
    }
  }

  // Direct per-line quantities (no lineage resolution)
  const enrichedLines = lines.map((line) => {
    const billedQuantity = billedByLineId.get(line.id) ?? new Decimal(0);
    const qty = new Decimal(line.quantity);
    return {
      ...line,
      billedQuantity: billedQuantity.toString(),
      remainingQuantityToBill: Decimal.max(qty.minus(billedQuantity), 0).toString(),
    };
  });

  return ok({
    purchaseOrder: {
      ...purchaseOrder,
      lines: enrichedLines,
    },
  });
}
