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 [receiptLines, billLines, matchedBills, postedReceipts] =
    lineIds.length > 0
      ? await Promise.all([
          db
            .selectFrom("GoodsReceiptLine")
            .selectAll()
            .where("purchaseOrderLineId", "in", lineIds)
            .execute(),
          db
            .selectFrom("PurchaseBillLine")
            .selectAll()
            .where("purchaseOrderLineId", "in", lineIds)
            .execute(),
          db.selectFrom("PurchaseBill").selectAll().where("status", "=", "MATCHED").execute(),
          db.selectFrom("GoodsReceipt").selectAll().where("status", "=", "POSTED").execute(),
        ])
      : [[], [], [], []];

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

  // Received quantity per PO line ID (from POSTED receipts only)
  const receivedByLineId = new Map<string, Decimal>();
  for (const rl of receiptLines) {
    if (rl.purchaseOrderLineId && postedReceiptIdSet.has(rl.goodsReceiptId)) {
      receivedByLineId.set(
        rl.purchaseOrderLineId,
        (receivedByLineId.get(rl.purchaseOrderLineId) ?? new Decimal(0)).plus(rl.quantity),
      );
    }
  }

  // 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 receivedQuantity = receivedByLineId.get(line.id) ?? new Decimal(0);
    const billedQuantity = billedByLineId.get(line.id) ?? new Decimal(0);
    const qty = new Decimal(line.quantity);
    return {
      ...line,
      receivedQuantity: receivedQuantity.toString(),
      billedQuantity: billedQuantity.toString(),
      remainingQuantityToReceive: Decimal.max(qty.minus(receivedQuantity), 0).toString(),
      remainingQuantityToBill: Decimal.max(qty.minus(billedQuantity), 0).toString(),
    };
  });

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