import { prisma } from '@/lib/prisma';
import { sanitizeText } from '@/lib/sanitize';
import type { AdjustInventoryInput, CreateWarehouseInput } from '@/schemas/inventory.schema';

// ─── ALMACENES ────────────────────────────────────────────────────────────────

export async function listWarehouses() {
  return prisma.warehouse.findMany({
    where: { isActive: true },
    orderBy: { name: 'asc' },
  });
}

export async function createWarehouse(data: CreateWarehouseInput) {
  return prisma.warehouse.create({
    data: { name: sanitizeText(data.name), description: data.description ? sanitizeText(data.description) : undefined },
  });
}

export async function updateWarehouse(id: string, data: Partial<CreateWarehouseInput>) {
  return prisma.warehouse.update({
    where: { id },
    data: {
      ...(data.name ? { name: sanitizeText(data.name) } : {}),
      ...(data.description !== undefined ? { description: sanitizeText(data.description) } : {}),
    },
  });
}

// ─── INVENTARIO ───────────────────────────────────────────────────────────────

export async function getInventory(warehouseId?: string, page = 1, limit = 20) {
  const skip = (page - 1) * limit;
  const where = warehouseId ? { warehouseId } : {};

  const [items, total] = await prisma.$transaction([
    prisma.inventory.findMany({
      where,
      skip,
      take: limit,
      include: {
        product: { select: { id: true, name: true, sku: true, unitMeasure: true, type: true } },
        warehouse: { select: { id: true, name: true } },
      },
      orderBy: [{ warehouse: { name: 'asc' } }, { product: { name: 'asc' } }],
    }),
    prisma.inventory.count({ where }),
  ]);

  return { items, total, page, limit };
}

export async function getLowStockAlerts(warehouseId?: string) {
  const where = {
    ...(warehouseId ? { warehouseId } : {}),
  };

  const items = await prisma.inventory.findMany({
    where,
    include: {
      product: { select: { id: true, name: true, sku: true, unitMeasure: true } },
      warehouse: { select: { id: true, name: true } },
    },
  });

  // Filtrar en memoria los que están bajo el mínimo
  return items.filter((item) => Number(item.quantity) <= Number(item.minStock));
}

export async function adjustInventory(data: AdjustInventoryInput, userId: string) {
  return prisma.$transaction(async (tx) => {
    // Asegurar que exista el registro de inventario (arranca en 0), sin pisar
    // la cantidad si ya existe.
    await tx.inventory.upsert({
      where: { productId_warehouseId: { productId: data.productId, warehouseId: data.warehouseId } },
      create: { productId: data.productId, warehouseId: data.warehouseId, quantity: 0, minStock: 5 },
      update: {},
    });

    const includeArgs = {
      product: { select: { id: true, name: true, unitMeasure: true } },
      warehouse: { select: { id: true, name: true } },
    } as const;

    let updated;
    if (data.quantity >= 0) {
      // Incremento: siempre seguro, no necesita guardia.
      updated = await tx.inventory.update({
        where: { productId_warehouseId: { productId: data.productId, warehouseId: data.warehouseId } },
        data: { quantity: { increment: data.quantity } },
        include: includeArgs,
      });
    } else {
      // Decremento atómico con guardia: el UPDATE solo aplica si alcanza el
      // stock, en el mismo statement — sin ventana entre leer y escribir.
      const decrementBy = Math.abs(data.quantity);
      const result = await tx.inventory.updateMany({
        where: { productId: data.productId, warehouseId: data.warehouseId, quantity: { gte: decrementBy } },
        data: { quantity: { decrement: decrementBy } },
      });
      if (result.count === 0) throw new Error('INSUFFICIENT_STOCK');

      updated = await tx.inventory.findUniqueOrThrow({
        where: { productId_warehouseId: { productId: data.productId, warehouseId: data.warehouseId } },
        include: includeArgs,
      });
    }

    // Registrar movimiento en Kardex
    await tx.stockMovement.create({
      data: {
        productId: data.productId,
        warehouseId: data.warehouseId,
        type: data.type,
        quantity: data.quantity,
        balance: Number(updated.quantity),
        reason: sanitizeText(data.reason),
        userId,
      },
    });

    return updated;
  });
}

export async function getStockMovements(filters: { productId?: string; warehouseId?: string; page?: number; limit?: number }) {
  const page = filters.page || 1;
  const limit = filters.limit || 50;
  const skip = (page - 1) * limit;

  const where = {
    ...(filters.productId ? { productId: filters.productId } : {}),
    ...(filters.warehouseId ? { warehouseId: filters.warehouseId } : {}),
  };

  const [movements, total] = await prisma.$transaction([
    prisma.stockMovement.findMany({
      where,
      skip,
      take: limit,
      include: {
        product: { select: { id: true, name: true, unitMeasure: true } },
        warehouse: { select: { id: true, name: true } },
      },
      orderBy: { createdAt: 'desc' },
    }),
    prisma.stockMovement.count({ where }),
  ]);

  return { movements, total, page, limit };
}
