<?php
// Prevenir acceso directo
if (!defined('BASEPATH')) exit('No direct script access allowed');

// La función getEstadoStock ya está definida en funciones.php

switch ($tipo) {
    case 'getProductos':
        try {
            $query = "SELECT
                p.id,
                p.nombre,
                p.descripcion,
                p.codigo_corto,
                p.codigo_barras,
                p.cve_cfdi,
                p.objeto_imp,
                p.tipo_factor_iva,
                p.tasa_iva,
                p.categoria_id,
                c.nombre as categoria_nombre,
                p.almacen_id,
                a.nombre as almacen_nombre,
                p.precio_compra,
                p.costo_precios,
                p.precio_lista,
                p.precio1,
                p.precio2,
                p.precio3,
                p.precio4,
                p.precio5,
                p.precio6,
                p.stock,
                p.stock_minimo,
                p.unidad_medida,
                p.impresora,
                p.activo,
                p.fecha_creacion,
                p.fecha_actualizacion,
                (SELECT COUNT(*) FROM producto_equivalencias pe WHERE pe.producto_equivalente_id = p.id AND pe.activo = 1) as es_base_equivalencia
            FROM productos p
            LEFT JOIN categorias c ON p.categoria_id = c.id
            LEFT JOIN almacenes a ON p.almacen_id = a.id
            WHERE p.activo = 1
            ORDER BY p.nombre ASC";

            $result = $conn->query($query);
            $productos = [];

            while ($row = $result->fetch_assoc()) {
                $productos[] = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_corto' => $row['codigo_corto'],
                    'codigo_barras' => $row['codigo_barras'],
                    'cve_cfdi' => $row['cve_cfdi'],
                    'objeto_imp' => $row['objeto_imp'] ?? '02',
                    'tipo_factor_iva' => $row['tipo_factor_iva'] ?? 'Tasa',
                    'tasa_iva' => ($row['tipo_factor_iva'] ?? 'Tasa') === 'Exento' ? 'exento' : floatval($row['tasa_iva'] ?? 0.16),
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'almacen_id' => $row['almacen_id'] ? intval($row['almacen_id']) : null,
                    'almacen_nombre' => $row['almacen_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'costo_precios' => floatval($row['costo_precios'] ?? 0),
                    'precio_lista' => floatval($row['precio_lista']),
                    'precio1' => floatval($row['precio1']),
                    'precio2' => floatval($row['precio2']),
                    'precio3' => floatval($row['precio3']),
                    'precio4' => floatval($row['precio4']),
                    'precio5' => floatval($row['precio5']),
                    'precio6' => floatval($row['precio6']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'impresora' => $row['impresora'],
                    'activo' => intval($row['activo']),
                    'fecha_creacion' => $row['fecha_creacion'],
                    'fecha_actualizacion' => $row['fecha_actualizacion'],
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo']),
                    'es_base_equivalencia' => intval($row['es_base_equivalencia'] ?? 0) > 0
                ];
            }

            sendResponse(true, "Productos obtenidos exitosamente", $productos);
        } catch (Exception $e) {
            sendResponse(false, "Error al obtener productos: " . $e->getMessage());
        }
        break;

    case 'getProductosParaPrecios':
        // Endpoint específico para cambio de precios
        // Excluye productos base que tengan equivalencias (muestra solo el equivalente mayor)
        $pagina = intval($datapost['pagina'] ?? 1);
        $limite = intval($datapost['limite'] ?? 50);
        $busqueda = trim($datapost['busqueda'] ?? '');
        $categoria_id = isset($datapost['categoria_id']) && $datapost['categoria_id'] !== '' ? intval($datapost['categoria_id']) : null;

        if ($pagina < 1) $pagina = 1;
        if ($limite < 1) $limite = 50;
        if ($limite > 100) $limite = 100;

        $offset = ($pagina - 1) * $limite;

        try {
            // Condición para excluir productos base que tengan equivalencias activas
            // Un producto BASE se excluye si existe en producto_equivalencias.producto_equivalente_id con activo=1
            // producto_id = producto equivalente (el grande)
            // producto_equivalente_id = producto base (el unitario)
            $whereConditions = [
                "p.activo = 1",
                "p.id NOT IN (SELECT pe.producto_equivalente_id FROM producto_equivalencias pe WHERE pe.activo = 1)"
            ];
            $params = [];
            $types = "";

            if (!empty($busqueda)) {
                $whereConditions[] = "(p.nombre LIKE ? OR p.codigo_barras LIKE ? OR p.codigo_corto LIKE ?)";
                $searchTerm = "%$busqueda%";
                $params[] = $searchTerm;
                $params[] = $searchTerm;
                $params[] = $searchTerm;
                $types .= "sss";
            }

            if ($categoria_id !== null) {
                $whereConditions[] = "p.categoria_id = ?";
                $params[] = $categoria_id;
                $types .= "i";
            }

            $whereClause = implode(" AND ", $whereConditions);

            // Query para contar el total
            $countQuery = "SELECT COUNT(*) as total FROM productos p WHERE $whereClause";
            $stmtCount = $conn->prepare($countQuery);
            if (!empty($params)) {
                $stmtCount->bind_param($types, ...$params);
            }
            $stmtCount->execute();
            $countResult = $stmtCount->get_result();
            $totalRow = $countResult->fetch_assoc();
            $total = intval($totalRow['total']);
            $stmtCount->close();

            // Query para obtener productos
            $query = "SELECT
                p.id,
                p.nombre,
                p.descripcion,
                p.codigo_corto,
                p.codigo_barras,
                p.categoria_id,
                c.nombre as categoria_nombre,
                p.almacen_id,
                a.nombre as almacen_nombre,
                p.precio_compra,
                p.costo_precios,
                p.precio_lista,
                p.precio1,
                p.precio2,
                p.precio3,
                p.precio4,
                p.precio5,
                p.precio6,
                p.stock,
                p.stock_minimo,
                p.unidad_medida,
                p.impresora,
                p.activo,
                (SELECT dv.cantidad_minima FROM descuentos_volumen dv WHERE dv.producto_id = p.id AND dv.activo = 1 ORDER BY dv.cantidad_minima ASC LIMIT 1) as cantidad_descuento,
                (SELECT dv.descuento_porcentaje FROM descuentos_volumen dv WHERE dv.producto_id = p.id AND dv.activo = 1 ORDER BY dv.cantidad_minima ASC LIMIT 1) as porcentaje_descuento
            FROM productos p
            LEFT JOIN categorias c ON p.categoria_id = c.id
            LEFT JOIN almacenes a ON p.almacen_id = a.id
            WHERE $whereClause
            ORDER BY p.nombre ASC
            LIMIT ? OFFSET ?";

            $params[] = $limite;
            $params[] = $offset;
            $types .= "ii";

            $stmt = $conn->prepare($query);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();
            $productos = [];

            while ($row = $result->fetch_assoc()) {
                $productos[] = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_corto' => $row['codigo_corto'],
                    'codigo_barras' => $row['codigo_barras'],
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'almacen_id' => $row['almacen_id'] ? intval($row['almacen_id']) : null,
                    'almacen_nombre' => $row['almacen_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'costo_precios' => floatval($row['costo_precios'] ?? 0),
                    'precio_lista' => floatval($row['precio_lista']),
                    'precio1' => floatval($row['precio1']),
                    'precio2' => floatval($row['precio2']),
                    'precio3' => floatval($row['precio3']),
                    'precio4' => floatval($row['precio4']),
                    'precio5' => floatval($row['precio5']),
                    'precio6' => floatval($row['precio6']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'impresora' => $row['impresora'],
                    'activo' => intval($row['activo']),
                    'es_base' => intval($row['es_base'] ?? 1),
                    'cantidad_descuento' => $row['cantidad_descuento'] ? floatval($row['cantidad_descuento']) : 0,
                    'porcentaje_descuento' => $row['porcentaje_descuento'] ? floatval($row['porcentaje_descuento']) : 0,
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo'])
                ];
            }
            $stmt->close();

            $totalPaginas = ceil($total / $limite);
            $hayMas = $pagina < $totalPaginas;

            sendResponse(true, "Productos obtenidos exitosamente", [
                'productos' => $productos,
                'paginacion' => [
                    'pagina' => $pagina,
                    'limite' => $limite,
                    'total' => $total,
                    'total_paginas' => $totalPaginas,
                    'hay_mas' => $hayMas
                ]
            ]);
        } catch (Exception $e) {
            sendResponse(false, "Error al obtener productos: " . $e->getMessage());
        }
        break;

    case 'getProductosPaginados':
        $pagina = intval($datapost['pagina'] ?? 1);
        $limite = intval($datapost['limite'] ?? 50);
        $busqueda = trim($datapost['busqueda'] ?? '');
        $categoria_id = isset($datapost['categoria_id']) && $datapost['categoria_id'] !== '' ? intval($datapost['categoria_id']) : null;
        $incluir_descuentos = isset($datapost['incluir_descuentos']) && $datapost['incluir_descuentos'];

        if ($pagina < 1) $pagina = 1;
        if ($limite < 1) $limite = 50;
        if ($limite > 100) $limite = 100;

        $offset = ($pagina - 1) * $limite;

        try {
            // Construir condiciones WHERE dinámicamente
            $whereConditions = ["p.activo = 1", "p.es_base = 1"];
            $params = [];
            $types = "";

            if (!empty($busqueda)) {
                $whereConditions[] = "(p.nombre LIKE ? OR p.codigo_barras LIKE ? OR p.codigo_corto LIKE ?)";
                $searchTerm = "%$busqueda%";
                $params[] = $searchTerm;
                $params[] = $searchTerm;
                $params[] = $searchTerm;
                $types .= "sss";
            }

            if ($categoria_id !== null) {
                $whereConditions[] = "p.categoria_id = ?";
                $params[] = $categoria_id;
                $types .= "i";
            }

            $whereClause = implode(" AND ", $whereConditions);

            // Query para contar el total
            $countQuery = "SELECT COUNT(*) as total FROM productos p WHERE $whereClause";
            $stmtCount = $conn->prepare($countQuery);
            if (!empty($params)) {
                $stmtCount->bind_param($types, ...$params);
            }
            $stmtCount->execute();
            $countResult = $stmtCount->get_result();
            $totalRow = $countResult->fetch_assoc();
            $total = intval($totalRow['total']);
            $stmtCount->close();

            // Query para obtener productos paginados con cantidad de descuento
            $query = "SELECT
                p.id,
                p.nombre,
                p.descripcion,
                p.codigo_corto,
                p.codigo_barras,
                p.categoria_id,
                c.nombre as categoria_nombre,
                p.almacen_id,
                a.nombre as almacen_nombre,
                p.precio_compra,
                p.costo_precios,
                p.precio_lista,
                p.precio1,
                p.precio2,
                p.precio3,
                p.precio4,
                p.precio5,
                p.precio6,
                p.stock,
                p.stock_minimo,
                p.unidad_medida,
                p.impresora,
                p.activo,
                p.es_base,
                (SELECT dv.cantidad_minima FROM descuentos_volumen dv WHERE dv.producto_id = p.id AND dv.activo = 1 ORDER BY dv.cantidad_minima ASC LIMIT 1) as cantidad_descuento,
                (SELECT dv.descuento_porcentaje FROM descuentos_volumen dv WHERE dv.producto_id = p.id AND dv.activo = 1 ORDER BY dv.cantidad_minima ASC LIMIT 1) as porcentaje_descuento
            FROM productos p
            LEFT JOIN categorias c ON p.categoria_id = c.id
            LEFT JOIN almacenes a ON p.almacen_id = a.id
            WHERE $whereClause
            ORDER BY p.nombre ASC
            LIMIT ? OFFSET ?";

            // Agregar parámetros de paginación
            $params[] = $limite;
            $params[] = $offset;
            $types .= "ii";

            $stmt = $conn->prepare($query);
            $stmt->bind_param($types, ...$params);
            $stmt->execute();
            $result = $stmt->get_result();
            $productos = [];

            while ($row = $result->fetch_assoc()) {
                $productos[] = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_corto' => $row['codigo_corto'],
                    'codigo_barras' => $row['codigo_barras'],
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'almacen_id' => $row['almacen_id'] ? intval($row['almacen_id']) : null,
                    'almacen_nombre' => $row['almacen_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'costo_precios' => floatval($row['costo_precios'] ?? 0),
                    'precio_lista' => floatval($row['precio_lista']),
                    'precio1' => floatval($row['precio1']),
                    'precio2' => floatval($row['precio2']),
                    'precio3' => floatval($row['precio3']),
                    'precio4' => floatval($row['precio4']),
                    'precio5' => floatval($row['precio5']),
                    'precio6' => floatval($row['precio6']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'impresora' => $row['impresora'],
                    'activo' => intval($row['activo']),
                    'es_base' => intval($row['es_base'] ?? 1),
                    'cantidad_descuento' => $row['cantidad_descuento'] ? floatval($row['cantidad_descuento']) : 0,
                    'porcentaje_descuento' => $row['porcentaje_descuento'] ? floatval($row['porcentaje_descuento']) : 0,
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo'])
                ];
            }
            $stmt->close();

            $totalPaginas = ceil($total / $limite);
            $hayMas = $pagina < $totalPaginas;

            sendResponse(true, "Productos obtenidos exitosamente", [
                'productos' => $productos,
                'paginacion' => [
                    'pagina' => $pagina,
                    'limite' => $limite,
                    'total' => $total,
                    'total_paginas' => $totalPaginas,
                    'hay_mas' => $hayMas
                ]
            ]);
        } catch (Exception $e) {
            sendResponse(false, "Error al obtener productos: " . $e->getMessage());
        }
        break;

    case 'getProducto':
        $id = intval($datapost['id'] ?? 0);

        if ($id <= 0) {
            sendResponse(false, "ID de producto requerido");
        }

        try {
            $query = "SELECT
                p.id,
                p.nombre,
                p.descripcion,
                p.codigo_corto,
                p.codigo_barras,
                p.cve_cfdi,
                p.objeto_imp,
                p.tipo_factor_iva,
                p.tasa_iva,
                p.categoria_id,
                c.nombre as categoria_nombre,
                p.almacen_id,
                a.nombre as almacen_nombre,
                p.precio_compra,
                p.costo_precios,
                p.precio_lista,
                p.precio1,
                p.precio2,
                p.precio3,
                p.precio4,
                p.precio5,
                p.precio6,
                p.stock,
                p.stock_minimo,
                p.unidad_medida,
                p.impresora,
                p.activo,
                p.fecha_creacion,
                p.fecha_actualizacion
            FROM productos p
            LEFT JOIN categorias c ON p.categoria_id = c.id
            LEFT JOIN almacenes a ON p.almacen_id = a.id
            WHERE p.id = ?";

            $stmt = $conn->prepare($query);
            $stmt->bind_param("i", $id);
            $stmt->execute();
            $result = $stmt->get_result();

            if ($row = $result->fetch_assoc()) {
                $producto = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_corto' => $row['codigo_corto'],
                    'codigo_barras' => $row['codigo_barras'],
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'almacen_id' => $row['almacen_id'] ? intval($row['almacen_id']) : null,
                    'almacen_nombre' => $row['almacen_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'costo_precios' => floatval($row['costo_precios'] ?? 0),
                    'precio_lista' => floatval($row['precio_lista']),
                    'precio1' => floatval($row['precio1']),
                    'precio2' => floatval($row['precio2']),
                    'precio3' => floatval($row['precio3']),
                    'precio4' => floatval($row['precio4']),
                    'precio5' => floatval($row['precio5']),
                    'precio6' => floatval($row['precio6']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'impresora' => $row['impresora'],
                    'activo' => intval($row['activo']),
                    'fecha_creacion' => $row['fecha_creacion'],
                    'fecha_actualizacion' => $row['fecha_actualizacion'],
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo'])
                ];
                sendResponse(true, "Producto obtenido exitosamente", $producto);
            } else {
                sendResponse(false, "Producto no encontrado");
            }
        } catch (Exception $e) {
            sendResponse(false, "Error al obtener producto: " . $e->getMessage());
        }
        break;

    case 'crearProducto':
        $nombre = trim($datapost['nombre'] ?? '');
        $descripcion = trim($datapost['descripcion'] ?? '');
        $codigo_corto = trim($datapost['codigo_corto'] ?? '');
        $codigo_barras = trim($datapost['codigo_barras'] ?? '');

        // Convertir cadenas vacías a NULL para campos únicos
        $codigo_corto = $codigo_corto === '' ? null : $codigo_corto;
        $codigo_barras = $codigo_barras === '' ? null : $codigo_barras;

        // Campos de facturación CFDI
        $cve_cfdi = isset($datapost['cve_cfdi']) && $datapost['cve_cfdi'] !== '' ? trim($datapost['cve_cfdi']) : null;
        $objeto_imp = trim($datapost['objeto_imp'] ?? '02');

        // Manejar tipo de factor IVA (Tasa o Exento)
        $tasa_iva_raw = $datapost['tasa_iva'] ?? '0.16';
        if ($tasa_iva_raw === 'exento') {
            $tipo_factor_iva = 'Exento';
            $tasa_iva = 0;
        } else {
            $tipo_factor_iva = 'Tasa';
            $tasa_iva = floatval($tasa_iva_raw);
        }

        $categoria_id = isset($datapost['categoria_id']) && $datapost['categoria_id'] !== '' ? intval($datapost['categoria_id']) : null;
        $almacen_id = isset($datapost['almacen_id']) && $datapost['almacen_id'] !== '' ? intval($datapost['almacen_id']) : null;
        $precio_compra = floatval($datapost['precio_compra'] ?? 0);
        $precio_lista = floatval($datapost['precio_lista'] ?? 0);
        $precio1 = floatval($datapost['precio1'] ?? 0);
        $precio2 = floatval($datapost['precio2'] ?? 0);
        $precio3 = floatval($datapost['precio3'] ?? 0);
        $precio4 = floatval($datapost['precio4'] ?? 0);
        $precio5 = floatval($datapost['precio5'] ?? 0);
        $precio6 = floatval($datapost['precio6'] ?? 0);
        $stock = intval($datapost['stock'] ?? 0);
        $stock_minimo = intval($datapost['stock_minimo'] ?? 0);
        $unidad_medida = trim($datapost['unidad_medida'] ?? 'pz');
        $impresora = isset($datapost['impresora']) && $datapost['impresora'] !== '' ? trim($datapost['impresora']) : null;
        $activo = isset($datapost['activo']) ? intval($datapost['activo']) : 1;
        $es_base = isset($datapost['es_base']) ? intval($datapost['es_base']) : 0;

        // Validaciones
        if (empty($nombre)) {
            sendResponse(false, "El nombre del producto es requerido");
        }

        if (strlen($nombre) > 100) {
            sendResponse(false, "El nombre no puede exceder 100 caracteres");
        }

        // Los precios son opcionales - si no se proporcionan se guardan como 0
        if ($precio_compra < 0) {
            sendResponse(false, "El precio de compra no puede ser negativo");
        }

        if ($precio_lista < 0) {
            sendResponse(false, "El precio de lista no puede ser negativo");
        }

        if ($stock < 0) {
            sendResponse(false, "El stock debe ser mayor o igual a 0");
        }

        if ($stock_minimo < 0) {
            sendResponse(false, "El stock mínimo debe ser mayor o igual a 0");
        }

        try {
            // Verificar código de barras único si se proporciona
            if ($codigo_barras !== null) {
                $checkBarcodeQuery = "SELECT id FROM productos WHERE codigo_barras = ?";
                $checkBarcodeStmt = $conn->prepare($checkBarcodeQuery);
                $checkBarcodeStmt->bind_param("s", $codigo_barras);
                $checkBarcodeStmt->execute();

                if ($checkBarcodeStmt->get_result()->num_rows > 0) {
                    sendResponse(false, "Ya existe un producto con ese código de barras");
                }
            }

            // Verificar que la categoría existe si se proporciona
            if ($categoria_id !== null) {
                $checkCategoryQuery = "SELECT id FROM categorias WHERE id = ? AND activo = 1";
                $checkCategoryStmt = $conn->prepare($checkCategoryQuery);
                $checkCategoryStmt->bind_param("i", $categoria_id);
                $checkCategoryStmt->execute();

                if ($checkCategoryStmt->get_result()->num_rows === 0) {
                    sendResponse(false, "La categoría seleccionada no existe o está inactiva");
                }
            }

            // Verificar que el almacén existe si se proporciona
            if ($almacen_id !== null) {
                $checkAlmacenQuery = "SELECT id FROM almacenes WHERE id = ? AND activo = 1";
                $checkAlmacenStmt = $conn->prepare($checkAlmacenQuery);
                $checkAlmacenStmt->bind_param("i", $almacen_id);
                $checkAlmacenStmt->execute();

                if ($checkAlmacenStmt->get_result()->num_rows === 0) {
                    sendResponse(false, "El almacén seleccionado no existe o está inactivo");
                }
            }

            // Crear el producto
            // Columnas: nombre(s), descripcion(s), codigo_corto(s), codigo_barras(s), cve_cfdi(s), objeto_imp(s), tipo_factor_iva(s), tasa_iva(d), categoria_id(i), almacen_id(i), precio_compra(d), precio_lista(d), precio1(d), precio2(d), precio3(d), precio4(d), precio5(d), precio6(d), stock(i), stock_minimo(i), unidad_medida(s), impresora(s), activo(i), es_base(i)
            $query = "INSERT INTO productos (nombre, descripcion, codigo_corto, codigo_barras, cve_cfdi, objeto_imp, tipo_factor_iva, tasa_iva, categoria_id, almacen_id, precio_compra, precio_lista, precio1, precio2, precio3, precio4, precio5, precio6, stock, stock_minimo, unidad_medida, impresora, activo, es_base) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            $stmt = $conn->prepare($query);
            $stmt->bind_param("sssssssdiiddddddddiissii", $nombre, $descripcion, $codigo_corto, $codigo_barras, $cve_cfdi, $objeto_imp, $tipo_factor_iva, $tasa_iva, $categoria_id, $almacen_id, $precio_compra, $precio_lista, $precio1, $precio2, $precio3, $precio4, $precio5, $precio6, $stock, $stock_minimo, $unidad_medida, $impresora, $activo, $es_base);

            if ($stmt->execute()) {
                $producto_id = $conn->insert_id;
                sendResponse(true, "Producto creado exitosamente", ['id' => $producto_id]);
            } else {
                sendResponse(false, "Error al crear el producto: " . $stmt->error);
            }
        } catch (Exception $e) {
            sendResponse(false, "Error al crear producto: " . $e->getMessage());
        }
        break;

    case 'actualizarProducto':
        $id = intval($datapost['id'] ?? 0);
        $nombre = trim($datapost['nombre'] ?? '');
        $descripcion = trim($datapost['descripcion'] ?? '');
        $codigo_corto = trim($datapost['codigo_corto'] ?? '');
        $codigo_barras = trim($datapost['codigo_barras'] ?? '');

        // Convertir cadenas vacías a NULL para campos únicos
        $codigo_corto = $codigo_corto === '' ? null : $codigo_corto;
        $codigo_barras = $codigo_barras === '' ? null : $codigo_barras;

        // Campos de facturación CFDI
        $cve_cfdi = isset($datapost['cve_cfdi']) && $datapost['cve_cfdi'] !== '' ? trim($datapost['cve_cfdi']) : null;
        $objeto_imp = trim($datapost['objeto_imp'] ?? '02');

        // Manejar tipo de factor IVA (Tasa o Exento)
        $tasa_iva_raw = $datapost['tasa_iva'] ?? '0.16';
        if ($tasa_iva_raw === 'exento') {
            $tipo_factor_iva = 'Exento';
            $tasa_iva = 0;
        } else {
            $tipo_factor_iva = 'Tasa';
            $tasa_iva = floatval($tasa_iva_raw);
        }

        $categoria_id = isset($datapost['categoria_id']) && $datapost['categoria_id'] !== '' ? intval($datapost['categoria_id']) : null;
        $almacen_id = isset($datapost['almacen_id']) && $datapost['almacen_id'] !== '' ? intval($datapost['almacen_id']) : null;
        $precio_compra = floatval($datapost['precio_compra'] ?? 0);
        $precio_lista = floatval($datapost['precio_lista'] ?? 0);
        $precio1 = floatval($datapost['precio1'] ?? 0);
        $precio2 = floatval($datapost['precio2'] ?? 0);
        $precio3 = floatval($datapost['precio3'] ?? 0);
        $precio4 = floatval($datapost['precio4'] ?? 0);
        $precio5 = floatval($datapost['precio5'] ?? 0);
        $precio6 = floatval($datapost['precio6'] ?? 0);
        $stock = intval($datapost['stock'] ?? 0);
        $stock_minimo = intval($datapost['stock_minimo'] ?? 0);
        $unidad_medida = trim($datapost['unidad_medida'] ?? 'pz');
        $impresora = isset($datapost['impresora']) && $datapost['impresora'] !== '' ? trim($datapost['impresora']) : null;
        $activo = isset($datapost['activo']) ? intval($datapost['activo']) : 1;
        $es_base = isset($datapost['es_base']) ? intval($datapost['es_base']) : 0;

        if ($id <= 0) {
            sendResponse(false, "ID de producto requerido");
        }

        // Validaciones
        if (empty($nombre)) {
            sendResponse(false, "El nombre del producto es requerido");
        }

        if (strlen($nombre) > 100) {
            sendResponse(false, "El nombre no puede exceder 100 caracteres");
        }

        // Los precios son opcionales - si no se proporcionan se guardan como 0
        if ($precio_compra < 0) {
            sendResponse(false, "El precio de compra no puede ser negativo");
        }

        if ($precio_lista < 0) {
            sendResponse(false, "El precio de lista no puede ser negativo");
        }

        if ($stock < 0) {
            sendResponse(false, "El stock debe ser mayor o igual a 0");
        }

        if ($stock_minimo < 0) {
            sendResponse(false, "El stock mínimo debe ser mayor o igual a 0");
        }

        try {
            // Verificar que el producto existe
            $checkQuery = "SELECT id FROM productos WHERE id = ?";
            $checkStmt = $conn->prepare($checkQuery);
            $checkStmt->bind_param("i", $id);
            $checkStmt->execute();

            if ($checkStmt->get_result()->num_rows === 0) {
                sendResponse(false, "Producto no encontrado");
            }

            // Verificar código de barras único si se proporciona
            if ($codigo_barras !== null) {
                $checkBarcodeQuery = "SELECT id FROM productos WHERE codigo_barras = ? AND id != ?";
                $checkBarcodeStmt = $conn->prepare($checkBarcodeQuery);
                $checkBarcodeStmt->bind_param("si", $codigo_barras, $id);
                $checkBarcodeStmt->execute();

                if ($checkBarcodeStmt->get_result()->num_rows > 0) {
                    sendResponse(false, "Ya existe otro producto con ese código de barras");
                }
            }

            // Verificar que la categoría existe si se proporciona
            if ($categoria_id !== null) {
                $checkCategoryQuery = "SELECT id FROM categorias WHERE id = ? AND activo = 1";
                $checkCategoryStmt = $conn->prepare($checkCategoryQuery);
                $checkCategoryStmt->bind_param("i", $categoria_id);
                $checkCategoryStmt->execute();

                if ($checkCategoryStmt->get_result()->num_rows === 0) {
                    sendResponse(false, "La categoría seleccionada no existe o está inactiva");
                }
            }

            // Verificar que el almacén existe si se proporciona
            if ($almacen_id !== null) {
                $checkAlmacenQuery = "SELECT id FROM almacenes WHERE id = ? AND activo = 1";
                $checkAlmacenStmt = $conn->prepare($checkAlmacenQuery);
                $checkAlmacenStmt->bind_param("i", $almacen_id);
                $checkAlmacenStmt->execute();

                if ($checkAlmacenStmt->get_result()->num_rows === 0) {
                    sendResponse(false, "El almacén seleccionado no existe o está inactivo");
                }
            }

            // Actualizar el producto
            // Tipos: nombre(s), descripcion(s), codigo_corto(s), codigo_barras(s), cve_cfdi(s), objeto_imp(s), tipo_factor_iva(s), tasa_iva(d), categoria_id(i), almacen_id(i), precio_compra(d), precio_lista(d), precio1-6(d), stock(i), stock_minimo(i), unidad_medida(s), impresora(s), activo(i), es_base(i), id(i)
            $query = "UPDATE productos SET nombre = ?, descripcion = ?, codigo_corto = ?, codigo_barras = ?, cve_cfdi = ?, objeto_imp = ?, tipo_factor_iva = ?, tasa_iva = ?, categoria_id = ?, almacen_id = ?, precio_compra = ?, precio_lista = ?, precio1 = ?, precio2 = ?, precio3 = ?, precio4 = ?, precio5 = ?, precio6 = ?, stock = ?, stock_minimo = ?, unidad_medida = ?, impresora = ?, activo = ?, es_base = ? WHERE id = ?";
            $stmt = $conn->prepare($query);
            $stmt->bind_param("sssssssdiiddddddddiissiii", $nombre, $descripcion, $codigo_corto, $codigo_barras, $cve_cfdi, $objeto_imp, $tipo_factor_iva, $tasa_iva, $categoria_id, $almacen_id, $precio_compra, $precio_lista, $precio1, $precio2, $precio3, $precio4, $precio5, $precio6, $stock, $stock_minimo, $unidad_medida, $impresora, $activo, $es_base, $id);

            if ($stmt->execute()) {
                sendResponse(true, "Producto actualizado exitosamente");
            } else {
                sendResponse(false, "Error al actualizar el producto: " . $stmt->error);
            }
        } catch (Exception $e) {
            sendResponse(false, "Error al actualizar producto: " . $e->getMessage());
        }
        break;

    case 'actualizarPrecios':
        $id = intval($datapost['id'] ?? 0);

        if ($id <= 0) {
            sendResponse(false, "ID de producto requerido");
        }

        try {
            $conn->begin_transaction();

            // Verificar que el producto existe
            $checkQuery = "SELECT id FROM productos WHERE id = ?";
            $checkStmt = $conn->prepare($checkQuery);
            $checkStmt->bind_param("i", $id);
            $checkStmt->execute();

            if ($checkStmt->get_result()->num_rows === 0) {
                $conn->rollback();
                sendResponse(false, "Producto no encontrado");
            }

            // Construir la consulta dinámicamente solo con los campos enviados
            $camposPermitidos = ['precio_compra', 'precio_lista', 'precio1', 'precio2', 'precio3', 'precio4', 'precio5', 'precio6'];
            $preciosActualizados = [];
            $setClauses = [];
            $params = [];
            $types = "";

            foreach ($camposPermitidos as $campo) {
                if (isset($datapost[$campo])) {
                    $valor = floatval($datapost[$campo]);
                    $setClauses[] = "$campo = ?";
                    $params[] = $valor;
                    $types .= "d";
                    $preciosActualizados[$campo] = $valor;
                }
            }

            if (empty($setClauses)) {
                $conn->rollback();
                sendResponse(false, "No se proporcionaron precios para actualizar");
            }

            // Agregar fecha de actualización
            $setClauses[] = "fecha_actualizacion = NOW()";

            // Agregar el ID al final de los parámetros
            $params[] = $id;
            $types .= "i";

            $query = "UPDATE productos SET " . implode(", ", $setClauses) . " WHERE id = ?";
            $stmt = $conn->prepare($query);
            $stmt->bind_param($types, ...$params);

            if (!$stmt->execute()) {
                $conn->rollback();
                sendResponse(false, "Error al actualizar precios: " . $stmt->error);
            }

            // Buscar si este producto es equivalente (el grande) de algún producto base
            // producto_id = producto equivalente (el grande)
            // producto_equivalente_id = producto base (el unitario)
            // Si lo es, actualizar el producto base dividiendo precios entre la cantidad
            $equivQuery = "SELECT pe.producto_equivalente_id as producto_base_id, pe.cantidad
                           FROM producto_equivalencias pe
                           WHERE pe.producto_id = ? AND pe.activo = 1";
            $equivStmt = $conn->prepare($equivQuery);
            $equivStmt->bind_param("i", $id);
            $equivStmt->execute();
            $equivResult = $equivStmt->get_result();

            $productosBaseActualizados = 0;
            while ($equivRow = $equivResult->fetch_assoc()) {
                $productoBaseId = intval($equivRow['producto_base_id']);
                $cantidadEquivalencia = floatval($equivRow['cantidad']);

                if ($cantidadEquivalencia > 0) {
                    // Calcular precios del producto base (precio equivalente / cantidad)
                    $setClausesBase = [];
                    $paramsBase = [];
                    $typesBase = "";

                    foreach ($preciosActualizados as $campo => $valor) {
                        $valorBase = round($valor / $cantidadEquivalencia, 2);
                        $setClausesBase[] = "$campo = ?";
                        $paramsBase[] = $valorBase;
                        $typesBase .= "d";
                    }

                    if (!empty($setClausesBase)) {
                        $setClausesBase[] = "fecha_actualizacion = NOW()";
                        $paramsBase[] = $productoBaseId;
                        $typesBase .= "i";

                        $queryBase = "UPDATE productos SET " . implode(", ", $setClausesBase) . " WHERE id = ?";
                        $stmtBase = $conn->prepare($queryBase);
                        $stmtBase->bind_param($typesBase, ...$paramsBase);

                        if ($stmtBase->execute()) {
                            $productosBaseActualizados++;
                        }
                    }
                }
            }

            $conn->commit();

            $mensaje = "Precios actualizados exitosamente";
            if ($productosBaseActualizados > 0) {
                $mensaje .= ". Se actualizaron $productosBaseActualizados producto(s) base por equivalencia.";
            }
            sendResponse(true, $mensaje);

        } catch (Exception $e) {
            $conn->rollback();
            sendResponse(false, "Error al actualizar precios: " . $e->getMessage());
        }
        break;

    case 'eliminarProducto':
        $id = intval($datapost['id'] ?? 0);

        if ($id <= 0) {
            sendResponse(false, "ID de producto requerido");
        }

        try {
            // Verificar que el producto existe
            $checkQuery = "SELECT nombre FROM productos WHERE id = ?";
            $checkStmt = $conn->prepare($checkQuery);
            $checkStmt->bind_param("i", $id);
            $checkStmt->execute();
            $checkResult = $checkStmt->get_result();

            if ($checkResult->num_rows === 0) {
                sendResponse(false, "Producto no encontrado");
            }

            // Verificar si tiene ventas asociadas (opcional - comentado por ahora)
            // $ventasQuery = "SELECT COUNT(*) as count FROM detalle_ventas WHERE producto_id = ?";
            // $ventasStmt = $conn->prepare($ventasQuery);
            // $ventasStmt->bind_param("i", $id);
            // $ventasStmt->execute();
            // $ventasResult = $ventasStmt->get_result();
            // $ventasCount = $ventasResult->fetch_assoc()['count'];

            // if ($ventasCount > 0) {
            //     sendResponse(false, "No se puede eliminar el producto porque tiene ventas asociadas");
            // }

            // Marcar el producto como inactivo (soft delete)
            $updateQuery = "UPDATE productos SET activo = 0 WHERE id = ?";
            $updateStmt = $conn->prepare($updateQuery);
            $updateStmt->bind_param("i", $id);

            if ($updateStmt->execute()) {
                sendResponse(true, "Producto desactivado exitosamente");
            } else {
                sendResponse(false, "Error al desactivar el producto");
            }
        } catch (Exception $e) {
            sendResponse(false, "Error al eliminar producto: " . $e->getMessage());
        }
        break;

    case 'buscarProductos':
        $query_search = trim($datapost['query'] ?? '');

        if (empty($query_search)) {
            sendResponse(false, "Término de búsqueda requerido");
        }

        try {
            // Detectar si la búsqueda es numérica
            $esNumerico = ctype_digit($query_search);
            $longitudBusqueda = strlen($query_search);

            // Códigos de barras largos (6+ dígitos) = búsqueda exacta por código de barras
            // Códigos cortos (5 dígitos o menos) = búsqueda por código corto o nombre (NO código de barras)
            $esCodigoBarrasLargo = $esNumerico && $longitudBusqueda >= 6;
            $esCodigoCortoNumerico = $esNumerico && $longitudBusqueda <= 5;

            if ($esCodigoBarrasLargo) {
                // Búsqueda exacta para códigos de barras largos (lector de código de barras)
                $query = "SELECT
                    p.id,
                    p.nombre,
                    p.descripcion,
                    p.codigo_corto,
                    p.codigo_barras,
                    p.categoria_id,
                    c.nombre as categoria_nombre,
                    p.precio_compra,
                    p.costo_precios,
                    p.precio_lista,
                    p.precio1,
                    p.precio2,
                    p.precio3,
                    p.precio4,
                    p.precio5,
                    p.precio6,
                    p.stock,
                    p.stock_minimo,
                    p.unidad_medida,
                    p.impresora,
                    p.activo,
                    p.es_base
                FROM productos p
                LEFT JOIN categorias c ON p.categoria_id = c.id
                WHERE p.activo = 1 AND p.es_base = 1 AND (
                    p.codigo_barras = ? OR
                    p.codigo_corto = ?
                )
                ORDER BY p.nombre ASC
                LIMIT 50";

                $stmt = $conn->prepare($query);
                $stmt->bind_param("ss", $query_search, $query_search);
            } else if ($esCodigoCortoNumerico) {
                // Búsqueda para números cortos (1-5 dígitos): solo código corto o nombre, NO código de barras
                $query = "SELECT
                    p.id,
                    p.nombre,
                    p.descripcion,
                    p.codigo_corto,
                    p.codigo_barras,
                    p.categoria_id,
                    c.nombre as categoria_nombre,
                    p.precio_compra,
                    p.costo_precios,
                    p.precio_lista,
                    p.precio1,
                    p.precio2,
                    p.precio3,
                    p.precio4,
                    p.precio5,
                    p.precio6,
                    p.stock,
                    p.stock_minimo,
                    p.unidad_medida,
                    p.impresora,
                    p.activo,
                    p.es_base
                FROM productos p
                LEFT JOIN categorias c ON p.categoria_id = c.id
                WHERE p.activo = 1 AND p.es_base = 1 AND (
                    p.codigo_corto LIKE ? OR
                    p.nombre LIKE ?
                )
                ORDER BY p.nombre ASC
                LIMIT 50";

                $searchTerm = "%{$query_search}%";
                $stmt = $conn->prepare($query);
                $stmt->bind_param("ss", $searchTerm, $searchTerm);
            } else {
                // Búsqueda por palabras individuales (más flexible)
                // Divide "marlin 400" en ["marlin", "400"] y busca productos que contengan TODAS las palabras
                $palabras = preg_split('/\s+/', $query_search);
                $palabras = array_filter($palabras, function($p) { return strlen($p) >= 2; }); // mínimo 2 caracteres

                if (count($palabras) > 1) {
                    // Búsqueda multi-palabra: cada palabra debe coincidir (AND)
                    $condiciones = [];
                    $params = [];
                    $types = "";

                    foreach ($palabras as $palabra) {
                        // Para palabras de 4+ caracteres, quitamos la última letra para tolerancia a errores
                        // Ej: "marlin" -> busca "%marli%" que encuentra "MARLI"
                        $palabraBusqueda = (strlen($palabra) >= 4) ? substr($palabra, 0, -1) : $palabra;
                        $termino = "%{$palabraBusqueda}%";
                        $condiciones[] = "(p.nombre LIKE ? OR p.descripcion LIKE ?)";
                        $params[] = $termino;
                        $params[] = $termino;
                        $types .= "ss";
                    }

                    $whereClause = implode(" AND ", $condiciones);

                    $query = "SELECT
                        p.id,
                        p.nombre,
                        p.descripcion,
                        p.codigo_corto,
                        p.codigo_barras,
                        p.categoria_id,
                        c.nombre as categoria_nombre,
                        p.precio_compra,
                        p.costo_precios,
                        p.precio_lista,
                        p.precio1,
                        p.precio2,
                        p.precio3,
                        p.precio4,
                        p.precio5,
                        p.precio6,
                        p.stock,
                        p.stock_minimo,
                        p.unidad_medida,
                        p.impresora,
                        p.activo,
                        p.es_base
                    FROM productos p
                    LEFT JOIN categorias c ON p.categoria_id = c.id
                    WHERE p.activo = 1 AND p.es_base = 1 AND ({$whereClause})
                    ORDER BY p.nombre ASC
                    LIMIT 50";

                    $stmt = $conn->prepare($query);
                    $stmt->bind_param($types, ...$params);
                } else {
                    // Búsqueda de una sola palabra (comportamiento original mejorado)
                    $palabraBusqueda = (strlen($query_search) >= 4) ? substr($query_search, 0, -1) : $query_search;

                    $query = "SELECT
                        p.id,
                        p.nombre,
                        p.descripcion,
                        p.codigo_corto,
                        p.codigo_barras,
                        p.categoria_id,
                        c.nombre as categoria_nombre,
                        p.precio_compra,
                        p.costo_precios,
                        p.precio_lista,
                        p.precio1,
                        p.precio2,
                        p.precio3,
                        p.precio4,
                        p.precio5,
                        p.precio6,
                        p.stock,
                        p.stock_minimo,
                        p.unidad_medida,
                        p.impresora,
                        p.activo,
                        p.es_base
                    FROM productos p
                    LEFT JOIN categorias c ON p.categoria_id = c.id
                    WHERE p.activo = 1 AND p.es_base = 1 AND (
                        p.nombre LIKE ? OR
                        p.descripcion LIKE ? OR
                        p.codigo_corto LIKE ?
                    )
                    ORDER BY p.nombre ASC
                    LIMIT 50";

                    $searchTerm = "%{$palabraBusqueda}%";
                    $stmt = $conn->prepare($query);
                    $stmt->bind_param("sss", $searchTerm, $searchTerm, $searchTerm);
                }
            }

            $stmt->execute();
            $result = $stmt->get_result();

            $productos = [];
            while ($row = $result->fetch_assoc()) {
                $productos[] = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_corto' => $row['codigo_corto'],
                    'codigo_barras' => $row['codigo_barras'],
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'costo_precios' => floatval($row['costo_precios'] ?? 0),
                    'precio_lista' => floatval($row['precio_lista']),
                    'precio1' => floatval($row['precio1']),
                    'precio2' => floatval($row['precio2']),
                    'precio3' => floatval($row['precio3']),
                    'precio4' => floatval($row['precio4']),
                    'precio5' => floatval($row['precio5']),
                    'precio6' => floatval($row['precio6']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'impresora' => $row['impresora'],
                    'activo' => intval($row['activo']),
                    'es_base' => intval($row['es_base'] ?? 1),
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo'])
                ];
            }

            sendResponse(true, "Búsqueda completada", $productos);
        } catch (Exception $e) {
            sendResponse(false, "Error en la búsqueda: " . $e->getMessage());
        }
        break;

    case 'getProductosPorCodigoBarras':
        $codigo = trim($datapost['codigo_barras'] ?? '');

        if (empty($codigo)) {
            sendResponse(false, "Código requerido");
        }

        try {
            $query = "SELECT
                p.id,
                p.nombre,
                p.descripcion,
                p.codigo_corto,
                p.codigo_barras,
                p.categoria_id,
                c.nombre as categoria_nombre,
                p.precio_compra,
                p.costo_precios,
                p.precio_lista,
                p.precio1,
                p.precio2,
                p.precio3,
                p.precio4,
                p.precio5,
                p.precio6,
                p.stock,
                p.stock_minimo,
                p.unidad_medida,
                p.impresora,
                p.activo
            FROM productos p
            LEFT JOIN categorias c ON p.categoria_id = c.id
            WHERE (p.codigo_barras = ? OR p.codigo_corto = ?) AND p.activo = 1";

            $stmt = $conn->prepare($query);
            $stmt->bind_param("ss", $codigo, $codigo);
            $stmt->execute();
            $result = $stmt->get_result();

            if ($row = $result->fetch_assoc()) {
                $producto = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_corto' => $row['codigo_corto'],
                    'codigo_barras' => $row['codigo_barras'],
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'costo_precios' => floatval($row['costo_precios'] ?? 0),
                    'precio_lista' => floatval($row['precio_lista']),
                    'precio1' => floatval($row['precio1']),
                    'precio2' => floatval($row['precio2']),
                    'precio3' => floatval($row['precio3']),
                    'precio4' => floatval($row['precio4']),
                    'precio5' => floatval($row['precio5']),
                    'precio6' => floatval($row['precio6']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'impresora' => $row['impresora'],
                    'activo' => intval($row['activo']),
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo'])
                ];
                sendResponse(true, "Producto encontrado", $producto);
            } else {
                sendResponse(false, "Producto no encontrado");
            }
        } catch (Exception $e) {
            sendResponse(false, "Error al buscar producto: " . $e->getMessage());
        }
        break;

    case 'actualizarStock':
        $id = intval($datapost['id'] ?? 0);
        $nuevo_stock = intval($datapost['stock'] ?? 0);
        $motivo = trim($datapost['motivo'] ?? '');

        if ($id <= 0) {
            sendResponse(false, "ID de producto requerido");
        }

        if ($nuevo_stock < 0) {
            sendResponse(false, "El stock debe ser mayor o igual a 0");
        }

        try {
            $query = "UPDATE productos SET stock = ? WHERE id = ?";
            $stmt = $conn->prepare($query);
            $stmt->bind_param("ii", $nuevo_stock, $id);

            if ($stmt->execute()) {
                sendResponse(true, "Stock actualizado exitosamente");
            } else {
                sendResponse(false, "Error al actualizar el stock");
            }
        } catch (Exception $e) {
            sendResponse(false, "Error al actualizar stock: " . $e->getMessage());
        }
        break;

    case 'getProductosBajoStock':
        try {
            $query = "SELECT
                p.id,
                p.nombre,
                p.descripcion,
                p.codigo_barras,
                p.categoria_id,
                c.nombre as categoria_nombre,
                p.precio_compra,
                p.precio_venta,
                p.stock,
                p.stock_minimo,
                p.unidad_medida
            FROM productos p
            LEFT JOIN categorias c ON p.categoria_id = c.id
            WHERE p.activo = 1 AND p.stock <= p.stock_minimo
            ORDER BY p.stock ASC, p.nombre ASC";

            $result = $conn->query($query);
            $productos = [];

            while ($row = $result->fetch_assoc()) {
                $productos[] = [
                    'id' => intval($row['id']),
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'],
                    'codigo_barras' => $row['codigo_barras'],
                    'categoria_id' => $row['categoria_id'] ? intval($row['categoria_id']) : null,
                    'categoria_nombre' => $row['categoria_nombre'],
                    'precio_compra' => floatval($row['precio_compra']),
                    'precio_venta' => floatval($row['precio_venta']),
                    'stock' => intval($row['stock']),
                    'stock_minimo' => intval($row['stock_minimo']),
                    'unidad_medida' => $row['unidad_medida'],
                    'estado_stock' => getEstadoStock($row['stock'], $row['stock_minimo'])
                ];
            }

            sendResponse(true, "Productos con bajo stock obtenidos", $productos);
        } catch (Exception $e) {
            sendResponse(false, "Error al obtener productos con bajo stock: " . $e->getMessage());
        }
        break;

    case 'importarProductos':
        $productos = $datapost['productos'] ?? [];

        if (empty($productos) || !is_array($productos)) {
            sendResponse(false, "Debe proporcionar un array de productos");
        }

        try {
            $conn->begin_transaction();

            $exitosos = 0;
            $fallidos = 0;
            $errores = [];

            foreach ($productos as $index => $producto) {
                try {
                    // Extraer datos del producto
                    $nombre = trim($producto['nombre'] ?? '');
                    $descripcion = trim($producto['descripcion'] ?? '');
                    $codigo_corto = trim($producto['codigo_corto'] ?? '');
                    $codigo_barras = trim($producto['codigo_barras'] ?? '');

                    // Convertir cadenas vacías a NULL para campos únicos
                    $codigo_corto = $codigo_corto === '' ? null : $codigo_corto;
                    $codigo_barras = $codigo_barras === '' ? null : $codigo_barras;

                    $categoria_id = isset($producto['categoria_id']) && $producto['categoria_id'] !== '' ? intval($producto['categoria_id']) : null;
                    $almacen_id = isset($producto['almacen_id']) && $producto['almacen_id'] !== '' ? intval($producto['almacen_id']) : null;
                    $precio_compra = floatval($producto['precio_compra'] ?? 0);
                    $precio1 = floatval($producto['precio1'] ?? 0);
                    $precio2 = floatval($producto['precio2'] ?? 0);
                    $precio3 = floatval($producto['precio3'] ?? 0);
                    $precio4 = floatval($producto['precio4'] ?? 0);
                    $stock = intval($producto['stock'] ?? 0);
                    $stock_minimo = intval($producto['stock_minimo'] ?? 5);
                    $unidad_medida = trim($producto['unidad_medida'] ?? 'pz');

                    // Validaciones
                    if (empty($nombre)) {
                        throw new Exception("Producto " . ($index + 1) . ": Nombre requerido");
                    }

                    if ($precio_compra <= 0) {
                        throw new Exception("Producto " . ($index + 1) . " ($nombre): Precio de compra inválido");
                    }

                    // Validar que al menos un precio esté configurado
                    if ($precio1 === 0 && $precio2 === 0 && $precio3 === 0 && $precio4 === 0) {
                        throw new Exception("Producto " . ($index + 1) . " ($nombre): Al menos un precio de venta requerido");
                    }

                    // Verificar código de barras único si se proporciona
                    if ($codigo_barras !== null) {
                        $checkBarcodeQuery = "SELECT id FROM productos WHERE codigo_barras = ?";
                        $checkBarcodeStmt = $conn->prepare($checkBarcodeQuery);
                        $checkBarcodeStmt->bind_param("s", $codigo_barras);
                        $checkBarcodeStmt->execute();

                        if ($checkBarcodeStmt->get_result()->num_rows > 0) {
                            throw new Exception("Producto " . ($index + 1) . " ($nombre): Código de barras duplicado");
                        }
                    }

                    // Insertar producto
                    $insertQuery = "INSERT INTO productos (nombre, descripcion, codigo_corto, codigo_barras, categoria_id, almacen_id, precio_compra, precio1, precio2, precio3, precio4, stock, stock_minimo, unidad_medida, activo) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1)";
                    $insertStmt = $conn->prepare($insertQuery);
                    $insertStmt->bind_param(
                        "ssssiidddddiis",
                        $nombre,
                        $descripcion,
                        $codigo_corto,
                        $codigo_barras,
                        $categoria_id,
                        $almacen_id,
                        $precio_compra,
                        $precio1,
                        $precio2,
                        $precio3,
                        $precio4,
                        $stock,
                        $stock_minimo,
                        $unidad_medida
                    );

                    if ($insertStmt->execute()) {
                        $exitosos++;
                    } else {
                        $fallidos++;
                        $errores[] = "Producto " . ($index + 1) . " ($nombre): Error al insertar";
                    }

                } catch (Exception $e) {
                    $fallidos++;
                    $errores[] = $e->getMessage();
                }
            }

            // Si hay al menos un producto exitoso, hacer commit
            if ($exitosos > 0) {
                $conn->commit();
            } else {
                $conn->rollback();
            }

            sendResponse(true, "Importación completada", [
                'total' => count($productos),
                'exitosos' => $exitosos,
                'fallidos' => $fallidos,
                'errores' => $errores
            ]);

        } catch (Exception $e) {
            $conn->rollback();
            sendResponse(false, "Error al importar productos: " . $e->getMessage());
        }
        break;

    case 'actualizarImpresorasMasivo':
        $productos = $datapost['productos'] ?? [];

        if (empty($productos) || !is_array($productos)) {
            sendResponse(false, "Debe proporcionar un array de productos");
        }

        try {
            $conn->begin_transaction();

            $exitosos = 0;
            $fallidos = 0;
            $errores = [];

            foreach ($productos as $index => $producto) {
                try {
                    $id = intval($producto['id'] ?? 0);
                    $impresora = isset($producto['impresora']) && $producto['impresora'] !== '' ? trim($producto['impresora']) : null;

                    if ($id <= 0) {
                        throw new Exception("Producto " . ($index + 1) . ": ID inválido");
                    }

                    // Verificar que el producto existe
                    $checkQuery = "SELECT id FROM productos WHERE id = ?";
                    $checkStmt = $conn->prepare($checkQuery);
                    $checkStmt->bind_param("i", $id);
                    $checkStmt->execute();

                    if ($checkStmt->get_result()->num_rows === 0) {
                        throw new Exception("Producto con ID " . $id . " no encontrado");
                    }

                    // Actualizar la impresora del producto
                    $updateQuery = "UPDATE productos SET impresora = ? WHERE id = ?";
                    $updateStmt = $conn->prepare($updateQuery);
                    $updateStmt->bind_param("si", $impresora, $id);

                    if ($updateStmt->execute()) {
                        $exitosos++;
                    } else {
                        $fallidos++;
                        $errores[] = "Error al actualizar producto ID " . $id;
                    }

                } catch (Exception $e) {
                    $fallidos++;
                    $errores[] = $e->getMessage();
                }
            }

            // Si hay al menos un producto exitoso, hacer commit
            if ($exitosos > 0) {
                $conn->commit();
            } else {
                $conn->rollback();
            }

            sendResponse(true, "Asignación de impresoras completada", [
                'total' => count($productos),
                'exitosos' => $exitosos,
                'fallidos' => $fallidos,
                'errores' => $errores
            ]);

        } catch (Exception $e) {
            $conn->rollback();
            sendResponse(false, "Error al asignar impresoras: " . $e->getMessage());
        }
        break;

    default:
        sendResponse(false, "Operación no válida para productos");
        break;
}
