/**
 * Centralized stock adjustment logic (per-warehouse + global fallback).
 */

async function syncProductQuantity(tx, productId) {
  const agg = await tx.warehouseStock.aggregate({
    where: { productId },
    _sum: { quantity: true },
  });
  const total = agg._sum.quantity ?? 0;
  await tx.product.update({
    where: { id: productId },
    data: { quantity: total },
  });
}

/**
 * @param {import("@prisma/client").PrismaClient} tx
 * @param {Array<{productId: string, quantity: number}>} lines
 * @param {1|-1} direction
 * @param {string|null|undefined} warehouseId
 */
async function adjustStock(tx, lines, direction, warehouseId) {
  for (const line of lines) {
    const qty = Math.abs(Math.floor(Number(line.quantity) || 0));
    if (!qty || !line.productId) continue;

    if (warehouseId) {
      const row = await tx.warehouseStock.findUnique({
        where: {
          warehouseId_productId: { warehouseId, productId: line.productId },
        },
      });
      const current = row?.quantity ?? 0;
      const next = current + direction * qty;
      if (direction < 0 && next < 0) {
        const product = await tx.product.findUnique({
          where: { id: line.productId },
          select: { name: true },
        });
        throw Object.assign(
          new Error(`Insufficient stock for ${product?.name || "product"} at this warehouse`),
          { status: 400 }
        );
      }
      await tx.warehouseStock.upsert({
        where: {
          warehouseId_productId: { warehouseId, productId: line.productId },
        },
        create: {
          warehouseId,
          productId: line.productId,
          quantity: Math.max(0, next),
        },
        update: { quantity: Math.max(0, next) },
      });
      await syncProductQuantity(tx, line.productId);
    } else {
      const product = await tx.product.findUnique({
        where: { id: line.productId },
        select: { quantity: true, name: true },
      });
      const next = (product?.quantity ?? 0) + direction * qty;
      if (direction < 0 && next < 0) {
        throw Object.assign(
          new Error(`Insufficient stock for ${product?.name || "product"}`),
          { status: 400 }
        );
      }
      await tx.product.update({
        where: { id: line.productId },
        data: { quantity: Math.max(0, next) },
      });
    }
  }
}

async function transferStock(tx, lines, fromWarehouseId, toWarehouseId) {
  if (!fromWarehouseId || !toWarehouseId) {
    throw Object.assign(new Error("Transfer requires from and to warehouses"), { status: 400 });
  }
  await adjustStock(tx, lines, -1, fromWarehouseId);
  await adjustStock(tx, lines, 1, toWarehouseId);
}

function stockTransition(oldStatus, newStatus, activeStatus) {
  const wasActive = oldStatus === activeStatus;
  const isActive = newStatus === activeStatus;

  if (!wasActive && isActive) return { apply: true, reverse: false };
  if (wasActive && !isActive) return { apply: false, reverse: true };
  return { apply: false, reverse: false };
}

module.exports = { adjustStock, transferStock, stockTransition, syncProductQuantity };
