import { db } from "@/lib/db";

/**
 * Product catalogue sync — registers a PO's line items as reusable `Product`s
 * (the `/catalogue/items` catalogue) and keeps last/per-vendor prices fresh:
 *  - line items with no `productId` are matched to an existing product by name,
 *    or a brand-new product is created, and the line item is linked back;
 *  - `lastPrice`/`lastVendorId` and the per-vendor price are upserted.
 *
 * Called at **approval** (so approved items are immediately reusable in further
 * POs) and again at **payment** (to refresh prices on the final figures). The
 * function is idempotent — re-running matches the same product by name/id.
 */
function nameToCode(name: string): string {
  const slug = name.toUpperCase()
    .replace(/[^A-Z0-9]+/g, "-")
    .replace(/^-|-$/g, "")
    .substring(0, 20);
  return `${slug}-${Date.now().toString(36).toUpperCase().slice(-5)}`;
}

export async function syncProductCatalog(
  poId: string,
  lineItems: { id: string; name: string; unitPrice: { toNumber(): number } | number; productId: string | null }[],
  vendorId: string | null,
  actorId: string
) {
  const updatedProductIds: string[] = [];

  for (const li of lineItems) {
    const unitPrice = typeof li.unitPrice === "number" ? li.unitPrice : li.unitPrice.toNumber();
    let productId = li.productId;
    let priceChanged = false;

    if (!productId) {
      // Try to find an existing product by name (case-insensitive)
      const existing = await db.product.findFirst({
        where: { name: { equals: li.name, mode: "insensitive" }, isActive: true },
        select: { id: true, lastPrice: true },
      });

      if (existing) {
        productId = existing.id;
        priceChanged = Number(existing.lastPrice ?? 0) !== unitPrice;
      } else {
        // Create a new product — first-time registration, not a price update
        const code = nameToCode(li.name);
        try {
          const created = await db.product.create({
            data: { code, name: li.name, lastPrice: unitPrice, lastVendorId: vendorId },
          });
          productId = created.id;
        } catch {
          // Code collision (extremely unlikely) — add extra entropy
          const created = await db.product.create({
            data: {
              code: `${code}-${Math.random().toString(36).slice(2, 5).toUpperCase()}`,
              name: li.name,
              lastPrice: unitPrice,
              lastVendorId: vendorId,
            },
          });
          productId = created.id;
        }
      }

      // Link the line item to the product for future reference
      await db.pOLineItem.update({ where: { id: li.id }, data: { productId } });
    } else {
      const current = await db.product.findUnique({
        where: { id: productId },
        select: { lastPrice: true },
      });
      priceChanged = !current || Number(current.lastPrice ?? 0) !== unitPrice;
    }

    // Always update lastPrice / lastVendorId on the product
    await db.product.update({
      where: { id: productId },
      data: { lastPrice: unitPrice, lastVendorId: vendorId ?? undefined },
    });

    // Upsert per-vendor price if PO has a vendor
    if (vendorId) {
      await db.productVendorPrice.upsert({
        where: { productId_vendorId: { productId, vendorId } },
        update: { price: unitPrice },
        create: { productId, vendorId, price: unitPrice },
      });
    }

    if (priceChanged) updatedProductIds.push(productId);
  }

  if (updatedProductIds.length > 0) {
    await db.pOAction.create({
      data: {
        actionType: "PRODUCT_PRICE_UPDATED",
        actorId,
        poId,
        metadata: { updatedProductIds },
      },
    });
  }
}
