<?php
class Producto
{
    private $conn;

    public function __construct($db)
    {
        $this->conn = $db;
    }

    public function obtenerTodos($filtros = [])
    {
        try {
            $where = ["p.id > 0"];
            $params = [];

            // Filtro por búsqueda
            if (!empty($filtros['search'])) {
                $where[] = "(p.nombre LIKE :search_nombre OR p.codigo LIKE :search_codigo)";
                $searchTerm = '%' . $filtros['search'] . '%';
                $params[':search_nombre'] = $searchTerm;
                $params[':search_codigo'] = $searchTerm;
            }

            // Filtro por categoría
            if (!empty($filtros['categoria_id'])) {
                $where[] = "p.categoria_id = :categoria_id";
                $params[':categoria_id'] = $filtros['categoria_id'];
            }

            // Filtro por estado
            if (isset($filtros['activo'])) {
                $where[] = "p.activo = :activo";
                $params[':activo'] = $filtros['activo'];
            }

            // Filtro por stock bajo
            if (!empty($filtros['stock_bajo'])) {
                $where[] = "p.stock_actual <= p.stock_minimo";
            }

            $whereClause = implode(' AND ', $where);

            $query = "SELECT
                        p.*,
                        c.nombre as categoria_nombre,
                        CASE
                            WHEN p.stock_actual <= p.stock_minimo THEN 'bajo'
                            WHEN p.stock_actual >= p.stock_maximo THEN 'alto'
                            ELSE 'normal'
                        END as estado_stock
                      FROM productos p
                      LEFT JOIN categorias_productos c ON p.categoria_id = c.id
                      WHERE $whereClause
                      ORDER BY COALESCE(p.orden, 999999) ASC, p.nombre ASC";

            error_log("Query productos: " . $query);
            error_log("Params: " . json_encode($params));

            $stmt = $this->conn->prepare($query);
            $stmt->execute($params);

            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log("Error obteniendo productos: " . $e->getMessage());
            return [];
        }
    }

    public function obtenerPorId($id)
    {
        try {
            $query = "SELECT 
                        p.*,
                        c.nombre as categoria_nombre
                      FROM productos p
                      LEFT JOIN categorias_productos c ON p.categoria_id = c.id
                      WHERE p.id = :id";

            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':id', $id);
            $stmt->execute();

            return $stmt->fetch(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log("Error obteniendo producto: " . $e->getMessage());
            return false;
        }
    }

    public function crear($datos)
    {
        try {
            // Verificar que el código no existe
            $checkQuery = "SELECT COUNT(*) as count FROM productos WHERE codigo = :codigo";
            $checkStmt = $this->conn->prepare($checkQuery);
            $checkStmt->bindParam(':codigo', $datos['codigo']);
            $checkStmt->execute();
            $result = $checkStmt->fetch(PDO::FETCH_ASSOC);

            if ($result['count'] > 0) {
                throw new Exception("El código del producto ya existe");
            }

            $query = "INSERT INTO productos (
                        codigo, nombre, categoria_id, precio, costo,
                        stock_actual, stock_minimo, stock_maximo, unidad_medida,
                        codigo_barras, imagen_url, activo
                      ) VALUES (
                        :codigo, :nombre, :categoria_id, :precio, :costo,
                        :stock_actual, :stock_minimo, :stock_maximo, :unidad_medida,
                        :codigo_barras, :imagen_url, :activo
                      )";

            $stmt = $this->conn->prepare($query);
            
            $stmt->bindParam(':codigo', $datos['codigo']);
            $stmt->bindParam(':nombre', $datos['nombre']);
            $stmt->bindParam(':categoria_id', $datos['categoria_id']);
            $stmt->bindParam(':precio', $datos['precio']);
            $stmt->bindParam(':costo', $datos['costo']);
            $stmt->bindParam(':stock_actual', $datos['stock_actual']);
            $stmt->bindParam(':stock_minimo', $datos['stock_minimo']);
            $stmt->bindParam(':stock_maximo', $datos['stock_maximo']);
            $stmt->bindParam(':unidad_medida', $datos['unidad_medida']);
            $stmt->bindParam(':codigo_barras', $datos['codigo_barras']);
            $stmt->bindParam(':imagen_url', $datos['imagen_url']);
            $stmt->bindParam(':activo', $datos['activo']);

            $stmt->execute();

            return $this->conn->lastInsertId();
        } catch (Exception $e) {
            error_log("Error creando producto: " . $e->getMessage());
            throw $e;
        }
    }

    public function actualizar($id, $datos)
    {
        try {
            error_log("Modelo Producto::actualizar - ID: $id, Datos: " . json_encode($datos));
            // Verificar que el código no existe en otro producto
            if (isset($datos['codigo'])) {
                $checkQuery = "SELECT COUNT(*) as count FROM productos WHERE codigo = :codigo AND id != :id";
                $checkStmt = $this->conn->prepare($checkQuery);
                $checkStmt->bindParam(':codigo', $datos['codigo']);
                $checkStmt->bindParam(':id', $id);
                $checkStmt->execute();
                $result = $checkStmt->fetch(PDO::FETCH_ASSOC);

                if ($result['count'] > 0) {
                    throw new Exception("El código del producto ya existe");
                }
            }

            $updateFields = [];
            $allowedFields = [
                'codigo', 'nombre', 'categoria_id', 'precio', 'costo',
                'stock_actual', 'stock_minimo', 'stock_maximo', 'unidad_medida',
                'codigo_barras', 'imagen_url', 'activo', 'orden'
            ];

            foreach ($allowedFields as $field) {
                if (isset($datos[$field])) {
                    $updateFields[] = "$field = :$field";
                }
            }

            if (empty($updateFields)) {
                throw new Exception("No hay datos para actualizar");
            }

            $query = "UPDATE productos SET " . implode(', ', $updateFields) . ", updated_at = CURRENT_TIMESTAMP WHERE id = :id";
            error_log("Query de actualización: " . $query);
            $stmt = $this->conn->prepare($query);

            foreach ($allowedFields as $field) {
                if (isset($datos[$field])) {
                    $stmt->bindValue(":$field", $datos[$field]);
                    error_log("Binding $field = " . $datos[$field]);
                }
            }
            $stmt->bindParam(':id', $id);
            error_log("Binding id = " . $id);

            $result = $stmt->execute();
            error_log("Resultado de execute(): " . ($result ? 'true' : 'false'));
            error_log("Filas afectadas: " . $stmt->rowCount());
            
            return $result;
        } catch (Exception $e) {
            error_log("Error actualizando producto: " . $e->getMessage());
            throw $e;
        }
    }

    public function eliminar($id)
    {
        try {
            // Soft delete
            $query = "UPDATE productos SET activo = 0, updated_at = CURRENT_TIMESTAMP WHERE id = :id";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':id', $id);

            return $stmt->execute();
        } catch (Exception $e) {
            error_log("Error eliminando producto: " . $e->getMessage());
            return false;
        }
    }

    public function obtenerCategorias()
    {
        try {
            $query = "SELECT * FROM categorias_productos WHERE activo = 1 ORDER BY nombre ASC";
            $stmt = $this->conn->prepare($query);
            $stmt->execute();

            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log("Error obteniendo categorías: " . $e->getMessage());
            return [];
        }
    }

    public function crearCategoria($nombre, $descripcion = null)
    {
        try {
            $query = "INSERT INTO categorias_productos (nombre, descripcion) VALUES (:nombre, :descripcion)";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':nombre', $nombre);
            $stmt->bindParam(':descripcion', $descripcion);

            $stmt->execute();
            return $this->conn->lastInsertId();
        } catch (Exception $e) {
            error_log("Error creando categoría: " . $e->getMessage());
            return false;
        }
    }

    public function actualizarStock($id, $nuevoStock, $motivoId = null, $motivoTexto = null, $usuarioId = null)
    {
        try {
            $this->conn->beginTransaction();

            // Obtener stock actual
            $query = "SELECT stock_actual FROM productos WHERE id = :id";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':id', $id);
            $stmt->execute();
            $stockAnterior = $stmt->fetchColumn();

            if ($stockAnterior === false) {
                throw new Exception("Producto no encontrado");
            }

            // Actualizar stock
            $query = "UPDATE productos SET stock_actual = :stock, updated_at = CURRENT_TIMESTAMP WHERE id = :id";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':stock', $nuevoStock);
            $stmt->bindParam(':id', $id);
            $stmt->execute();

            // Determinar motivo final
            $motivoFinal = 'Ajuste manual';
            if ($motivoId) {
                // Obtener el nombre del motivo
                $query = "SELECT nombre FROM motivos_stock WHERE id = :id";
                $stmt = $this->conn->prepare($query);
                $stmt->bindParam(':id', $motivoId);
                $stmt->execute();
                $motivoNombre = $stmt->fetchColumn();
                
                if ($motivoNombre) {
                    // Si es "Otro" y hay texto personalizado, usar el texto
                    if ($motivoNombre === 'Otro' && !empty($motivoTexto)) {
                        $motivoFinal = trim($motivoTexto);
                    } else {
                        $motivoFinal = $motivoNombre;
                    }
                }
            }

            // Registrar movimiento
            $tipoMovimiento = $nuevoStock > $stockAnterior ? 'entrada' : ($nuevoStock < $stockAnterior ? 'salida' : 'ajuste');
            $cantidad = abs($nuevoStock - $stockAnterior);

            $query = "INSERT INTO movimientos_stock (producto_id, tipo_movimiento, cantidad, stock_anterior, stock_nuevo, motivo, motivo_id, usuario_id) 
                      VALUES (:producto_id, :tipo, :cantidad, :stock_anterior, :stock_nuevo, :motivo, :motivo_id, :usuario_id)";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':producto_id', $id);
            $stmt->bindParam(':tipo', $tipoMovimiento);
            $stmt->bindParam(':cantidad', $cantidad);
            $stmt->bindParam(':stock_anterior', $stockAnterior);
            $stmt->bindParam(':stock_nuevo', $nuevoStock);
            $stmt->bindParam(':motivo', $motivoFinal);
            $stmt->bindParam(':motivo_id', $motivoId);
            $stmt->bindParam(':usuario_id', $usuarioId);
            $stmt->execute();

            $this->conn->commit();
            return true;
        } catch (Exception $e) {
            $this->conn->rollback();
            error_log("Error actualizando stock: " . $e->getMessage());
            throw $e;
        }
    }

    public function obtenerMovimientos($productoId = null, $limit = 50)
    {
        try {
            $where = "1=1";
            $params = [];

            if ($productoId) {
                $where = "ms.producto_id = :producto_id";
                $params[':producto_id'] = $productoId;
            }

            $query = "SELECT 
                        ms.*,
                        p.nombre as producto_nombre,
                        p.codigo as producto_codigo,
                        u.nombre as usuario_nombre
                      FROM movimientos_stock ms
                      LEFT JOIN productos p ON ms.producto_id = p.id
                      LEFT JOIN usuarios u ON ms.usuario_id = u.id
                      WHERE $where
                      ORDER BY ms.created_at DESC
                      LIMIT $limit";

            $stmt = $this->conn->prepare($query);
            $stmt->execute($params);

            return $stmt->fetchAll(PDO::FETCH_ASSOC);
        } catch (Exception $e) {
            error_log("Error obteniendo movimientos: " . $e->getMessage());
            return [];
        }
    }

    public function obtenerEstadisticas()
    {
        try {
            $stats = [];

            // Total productos
            $query = "SELECT COUNT(*) as total FROM productos WHERE activo = 1";
            $stmt = $this->conn->prepare($query);
            $stmt->execute();
            $stats['total_productos'] = $stmt->fetchColumn();

            // Productos con stock bajo
            $query = "SELECT COUNT(*) as total FROM productos WHERE activo = 1 AND stock_actual <= stock_minimo";
            $stmt = $this->conn->prepare($query);
            $stmt->execute();
            $stats['productos_stock_bajo'] = $stmt->fetchColumn();

            // Valor total inventario
            $query = "SELECT SUM(precio * stock_actual) as valor FROM productos WHERE activo = 1";
            $stmt = $this->conn->prepare($query);
            $stmt->execute();
            $stats['valor_inventario'] = $stmt->fetchColumn() ?: 0;

            // Total categorías
            $query = "SELECT COUNT(*) as total FROM categorias_productos WHERE activo = 1";
            $stmt = $this->conn->prepare($query);
            $stmt->execute();
            $stats['total_categorias'] = $stmt->fetchColumn();

            return $stats;
        } catch (Exception $e) {
            error_log("Error obteniendo estadísticas: " . $e->getMessage());
            return [];
        }
    }
}
?>