import { prisma } from '@/lib/prisma';
import { ItemStatus } from '@prisma/client';
import { VALID_TRANSITIONS } from '@/schemas/dispense.schema';
import { sanitizeText } from '@/lib/sanitize';

const BAR_WAREHOUSE_ID = 'warehouse-barra-principal';

export async function getPendingItems(status?: ItemStatus) {
  const statuses: ItemStatus[] = status ? [status] : ['PENDING', 'PREPARING'];

  return prisma.orderItem.findMany({
    where: { status: { in: statuses } },
    include: {
      product: {
        select: {
          id: true,
          name: true,
          type: true,
          recipeItems: {
            include: { ingredient: { select: { id: true, name: true, unitMeasure: true } } },
          },
        },
      },
      order: {
        select: {
          id: true,
          orderNumber: true,
          table: { select: { number: true, zone: { select: { name: true } } } },
          waiter: { select: { name: true } },
        },
      },
    },
    orderBy: { createdAt: 'asc' },
  });
}

export async function dispenseItem(
  itemId: string,
  newStatus: ItemStatus,
  bartenderId: string,
  cancelReason?: string
) {
  return prisma.$transaction(async (tx) => {
    const item = await tx.orderItem.findUnique({
      where: { id: itemId },
      include: {
        product: {
          include: { recipeItems: true },
        },
      },
    });

    if (!item) throw new Error('ORDER_NOT_FOUND');

    // Validar transición de estado
    const allowedNext = VALID_TRANSITIONS[item.status] || [];
    if (!allowedNext.includes(newStatus)) {
      throw new Error(`INVALID_STATUS: No se puede pasar de ${item.status} a ${newStatus}`);
    }

    // Descontar stock SOLO cuando se marca DISPENSED
    if (newStatus === 'DISPENSED') {
      if (item.product.type === 'RECIPE_COCKTAIL') {
        // Descontar cada ingrediente del BOM
        for (const ingredient of item.product.recipeItems) {
          const required = Number(ingredient.quantity) * item.quantity;

          // Descuento atómico: el UPDATE solo afecta la fila si hay stock
          // suficiente en el mismo statement, sin ventana entre leer y escribir.
          const decremented = await tx.inventory.updateMany({
            where: {
              productId: ingredient.ingredientId,
              warehouseId: BAR_WAREHOUSE_ID,
              quantity: { gte: required },
            },
            data: { quantity: { decrement: required } },
          });

          if (decremented.count === 0) {
            throw new Error(`INSUFFICIENT_STOCK`);
          }

          const updated = await tx.inventory.findUniqueOrThrow({
            where: {
              productId_warehouseId: {
                productId: ingredient.ingredientId,
                warehouseId: BAR_WAREHOUSE_ID,
              },
            },
          });

          await tx.stockMovement.create({
            data: {
              productId: ingredient.ingredientId,
              warehouseId: BAR_WAREHOUSE_ID,
              type: 'SALE',
              quantity: -required,
              balance: Number(updated.quantity),
              reason: `Dispensación: ${item.product.name} x${item.quantity}`,
              referenceId: item.orderId,
              userId: bartenderId,
            },
          });
        }
      } else if (item.product.type !== 'SUPPLY') {
        // Producto simple o fraccionable — mismo descuento atómico con guardia
        const decremented = await tx.inventory.updateMany({
          where: {
            productId: item.productId,
            warehouseId: BAR_WAREHOUSE_ID,
            quantity: { gte: item.quantity },
          },
          data: { quantity: { decrement: item.quantity } },
        });

        if (decremented.count === 0) {
          throw new Error('INSUFFICIENT_STOCK');
        }

        const updated = await tx.inventory.findUniqueOrThrow({
          where: {
            productId_warehouseId: { productId: item.productId, warehouseId: BAR_WAREHOUSE_ID },
          },
        });

        await tx.stockMovement.create({
          data: {
            productId: item.productId,
            warehouseId: BAR_WAREHOUSE_ID,
            type: 'SALE',
            quantity: -item.quantity,
            balance: Number(updated.quantity),
            reason: `Venta: ${item.product.name} x${item.quantity}`,
            referenceId: item.orderId,
            userId: bartenderId,
          },
        });
      }
    }

    // Actualizar estado del ítem
    const updateData: Record<string, unknown> = { status: newStatus };

    if (newStatus === 'DISPENSED') {
      updateData.dispensedAt = new Date();
      updateData.dispensedById = bartenderId;
    }
    if (newStatus === 'DELIVERED') {
      updateData.deliveredAt = new Date();
    }
    if (newStatus === 'CANCELLED') {
      updateData.cancelledAt = new Date();
      updateData.cancelReason = sanitizeText(cancelReason || '');
    }

    const updatedItem = await tx.orderItem.update({
      where: { id: itemId },
      data: updateData,
      include: {
        product: { select: { id: true, name: true } },
        order: { select: { id: true, orderNumber: true } },
      },
    });

    // Actualizar estado de la orden según items
    const remainingItems = await tx.orderItem.findMany({
      where: { orderId: item.orderId, status: { notIn: ['CANCELLED', 'DELIVERED'] } },
      select: { status: true },
    });

    let orderStatus: string | undefined;
    if (remainingItems.length === 0) {
      orderStatus = 'SERVED';
    } else if (remainingItems.some((i) => i.status === 'PREPARING' || i.status === 'DISPENSED')) {
      orderStatus = 'IN_PROGRESS';
    }

    if (orderStatus) {
      await tx.order.update({ where: { id: item.orderId }, data: { status: orderStatus as never } });
    }

    return updatedItem;
  });
}
