<?php

class Ruta
{
    private $conn;

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

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

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

            // Filtro por estado
            if (!empty($filtros['estado'])) {
                $where[] = "r.estado = :estado";
                $params[':estado'] = $filtros['estado'];
            }

            // Filtro por fecha
            if (!empty($filtros['fecha_inicio'])) {
                $where[] = "r.fecha_ruta >= :fecha_inicio";
                $params[':fecha_inicio'] = $filtros['fecha_inicio'];
            }

            if (!empty($filtros['fecha_fin'])) {
                $where[] = "r.fecha_ruta <= :fecha_fin";
                $params[':fecha_fin'] = $filtros['fecha_fin'];
            }

            // Filtro por repartidor
            if (!empty($filtros['repartidor_id'])) {
                $where[] = "r.repartidor_id = :repartidor_id";
                $params[':repartidor_id'] = $filtros['repartidor_id'];
            }

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

            $query = "SELECT 
                        r.*,
                        CONCAT(rep.nombre, ' ', rep.apellidos) as repartidor_nombre,
                        rep.telefono as repartidor_telefono,
                        v.marca as vehiculo_marca,
                        v.modelo as vehiculo_modelo,
                        v.placa as vehiculo_placa,
                        CONCAT(u.nombre, ' ', u.apellido) as creado_por,
                        (SELECT COUNT(*) FROM rutas_paradas rp WHERE rp.ruta_id = r.id) as total_paradas,
                        (SELECT COUNT(*) FROM rutas_paradas rp WHERE rp.ruta_id = r.id AND rp.estado = 'visitada') as paradas_visitadas
                      FROM rutas r
                      LEFT JOIN repartidores rep ON r.repartidor_id = rep.id
                      LEFT JOIN vehiculos v ON r.vehiculo_id = v.id
                      LEFT JOIN usuarios u ON r.created_by = u.id
                      WHERE $whereClause
                      ORDER BY r.fecha_ruta DESC, r.created_at DESC";

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

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

    public function obtenerPorId($id)
    {
        try {
            $query = "SELECT 
                        r.*,
                        CONCAT(rep.nombre, ' ', rep.apellidos) as repartidor_nombre,
                        rep.telefono as repartidor_telefono,
                        rep.email as repartidor_email,
                        v.marca as vehiculo_marca,
                        v.modelo as vehiculo_modelo,
                        v.placa as vehiculo_placa,
                        v.tipo as vehiculo_tipo,
                        CONCAT(u.nombre, ' ', u.apellido) as creado_por
                      FROM rutas r
                      LEFT JOIN repartidores rep ON r.repartidor_id = rep.id
                      LEFT JOIN vehiculos v ON r.vehiculo_id = v.id
                      LEFT JOIN usuarios u ON r.created_by = u.id
                      WHERE r.id = :id";

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

            $ruta = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($ruta) {
                // Obtener paradas de la ruta
                $ruta['paradas'] = $this->obtenerParadasRuta($id);
                
                // Obtener productos de la ruta (si existen)
                $ruta['productos'] = $this->obtenerProductosRuta($id);
            }

            return $ruta;
        } catch (Exception $e) {
            error_log("Error obteniendo ruta por ID: " . $e->getMessage());
            return null;
        }
    }

    public function crear($datos)
    {
        try {
            $this->conn->beginTransaction();

            // Generar código automático si no se proporciona
            if (empty($datos['codigo'])) {
                $datos['codigo'] = $this->generarCodigoAutomatico();
            }

            $query = "INSERT INTO rutas (
                        codigo, nombre, descripcion, fecha_ruta, hora_inicio, hora_fin,
                        estado, repartidor_id, vehiculo_id, notas, created_by,
                        distancia_total, tiempo_estimado, ruta_polyline, waypoints_optimizados,
                        bounds_ne_lat, bounds_ne_lng, bounds_sw_lat, bounds_sw_lng, instrucciones_json
                      ) VALUES (
                        :codigo, :nombre, :descripcion, :fecha_ruta, :hora_inicio, :hora_fin,
                        :estado, :repartidor_id, :vehiculo_id, :notas, :created_by,
                        :distancia_total, :tiempo_estimado, :ruta_polyline, :waypoints_optimizados,
                        :bounds_ne_lat, :bounds_ne_lng, :bounds_sw_lat, :bounds_sw_lng, :instrucciones_json
                      )";

            $stmt = $this->conn->prepare($query);
            
            $stmt->bindParam(':codigo', $datos['codigo']);
            $stmt->bindParam(':nombre', $datos['nombre']);
            $stmt->bindParam(':descripcion', $datos['descripcion']);
            $stmt->bindParam(':fecha_ruta', $datos['fecha_ruta']);
            $stmt->bindParam(':hora_inicio', $datos['hora_inicio']);
            $stmt->bindParam(':hora_fin', $datos['hora_fin']);
            $stmt->bindParam(':estado', $datos['estado']);
            $stmt->bindParam(':repartidor_id', $datos['repartidor_id']);
            $stmt->bindParam(':vehiculo_id', $datos['vehiculo_id']);
            $stmt->bindParam(':notas', $datos['notas']);
            $stmt->bindParam(':created_by', $datos['created_by']);
            
            // Bind route calculation parameters
            $distanciaTotal = $datos['distancia_total'] ?? null;
            $stmt->bindParam(':distancia_total', $distanciaTotal);
            
            $tiempoEstimado = $datos['tiempo_estimado'] ?? null;
            $stmt->bindParam(':tiempo_estimado', $tiempoEstimado);
            
            $rutaPolyline = $datos['ruta_polyline'] ?? null;
            $stmt->bindParam(':ruta_polyline', $rutaPolyline);
            
            $waypointsOptimizados = $datos['waypoints_optimizados'] ?? null;
            $stmt->bindParam(':waypoints_optimizados', $waypointsOptimizados);
            
            $boundsNeLat = $datos['bounds_ne_lat'] ?? null;
            $stmt->bindParam(':bounds_ne_lat', $boundsNeLat);
            
            $boundsNeLng = $datos['bounds_ne_lng'] ?? null;
            $stmt->bindParam(':bounds_ne_lng', $boundsNeLng);
            
            $boundsSwLat = $datos['bounds_sw_lat'] ?? null;
            $stmt->bindParam(':bounds_sw_lat', $boundsSwLat);
            
            $boundsSwLng = $datos['bounds_sw_lng'] ?? null;
            $stmt->bindParam(':bounds_sw_lng', $boundsSwLng);
            
            $instruccionesJson = $datos['instrucciones_json'] ?? null;
            $stmt->bindParam(':instrucciones_json', $instruccionesJson);

            $stmt->execute();
            $rutaId = $this->conn->lastInsertId();

            // Registrar en historial
            $this->registrarHistorial($rutaId, $datos['created_by'], 'creada', 'Ruta creada');

            $this->conn->commit();
            return $rutaId;

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

    public function actualizar($id, $datos)
    {
        try {
            $campos = [];
            $params = [':id' => $id];

            $allowedFields = [
                'codigo', 'nombre', 'descripcion', 'fecha_ruta', 'hora_inicio', 'hora_fin',
                'estado', 'repartidor_id', 'vehiculo_id', 'notas', 'distancia_total', 'tiempo_estimado',
                'ruta_polyline', 'waypoints_optimizados', 'bounds_ne_lat', 'bounds_ne_lng',
                'bounds_sw_lat', 'bounds_sw_lng', 'instrucciones_json'
            ];

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

            if (empty($campos)) {
                return false;
            }

            $query = "UPDATE rutas SET " . implode(', ', $campos) . " WHERE id = :id";
            
            $stmt = $this->conn->prepare($query);
            $result = $stmt->execute($params);

            // Registrar cambio en historial
            if ($result && isset($datos['usuario_id'])) {
                $this->registrarHistorial($id, $datos['usuario_id'], 'modificada', 'Ruta actualizada');
            }

            return $result;

        } catch (Exception $e) {
            error_log("Error actualizando ruta: " . $e->getMessage());
            throw $e;
        }
    }

    public function eliminar($id)
    {
        try {
            $this->conn->beginTransaction();

            // Eliminar paradas asociadas
            $stmt = $this->conn->prepare("DELETE FROM rutas_paradas WHERE ruta_id = :id");
            $stmt->bindParam(':id', $id);
            $stmt->execute();

            // Eliminar productos asociados
            $stmt = $this->conn->prepare("DELETE FROM ruta_productos WHERE ruta_id = :id");
            $stmt->bindParam(':id', $id);
            $stmt->execute();

            // Eliminar ruta
            $stmt = $this->conn->prepare("DELETE FROM rutas WHERE id = :id");
            $stmt->bindParam(':id', $id);
            $result = $stmt->execute();

            $this->conn->commit();
            return $result;

        } catch (Exception $e) {
            $this->conn->rollBack();
            error_log("Error eliminando ruta: " . $e->getMessage());
            throw $e;
        }
    }

    public function obtenerParadasRuta($rutaId)
    {
        try {
            $query = "SELECT 
                        rp.*,
                        c.codigo as cliente_codigo,
                        c.nombre_comercial,
                        CONCAT(c.nombre, ' ', COALESCE(c.apellidos, '')) as cliente_nombre,
                        c.telefono,
                        c.direccion,
                        c.latitud,
                        c.longitud
                      FROM rutas_paradas rp
                      INNER JOIN clientes c ON rp.cliente_id = c.id
                      WHERE rp.ruta_id = :ruta_id
                      ORDER BY rp.orden ASC";

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

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

    public function agregarParada($rutaId, $clienteId, $orden, $datos = [])
    {
        try {
            $query = "INSERT INTO rutas_paradas (
                        ruta_id, cliente_id, orden, tiempo_estimado, notas, 
                        frecuencia_dias, fecha_inicio_frecuencia, proxima_visita, dias_semana
                      ) VALUES (
                        :ruta_id, :cliente_id, :orden, :tiempo_estimado, :notas,
                        :frecuencia_dias, :fecha_inicio_frecuencia, :proxima_visita, :dias_semana
                      )";

            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':ruta_id', $rutaId);
            $stmt->bindParam(':cliente_id', $clienteId);
            $stmt->bindParam(':orden', $orden);
            
            $tiempoEstimado = $datos['tiempo_estimado'] ?? 15;
            $stmt->bindParam(':tiempo_estimado', $tiempoEstimado);
            
            $notas = $datos['notas'] ?? null;
            $stmt->bindParam(':notas', $notas);
            
            $frecuenciaDias = $datos['frecuencia_dias'] ?? null;
            $stmt->bindParam(':frecuencia_dias', $frecuenciaDias);
            
            $fechaInicioFrecuencia = $datos['fecha_inicio_frecuencia'] ?? null;
            $stmt->bindParam(':fecha_inicio_frecuencia', $fechaInicioFrecuencia);
            
            $proximaVisita = $datos['proxima_visita'] ?? null;
            $stmt->bindParam(':proxima_visita', $proximaVisita);
            
            $diasSemana = isset($datos['dias_semana']) && is_array($datos['dias_semana']) 
                         ? implode(',', $datos['dias_semana']) 
                         : null;
            $stmt->bindParam(':dias_semana', $diasSemana);

            return $stmt->execute();

        } catch (Exception $e) {
            error_log("Error agregando parada a ruta: " . $e->getMessage());
            throw $e;
        }
    }

    public function obtenerProductosRuta($rutaId)
    {
        try {
            $query = "SELECT 
                        rp.*,
                        p.nombre as producto_nombre,
                        p.codigo as producto_codigo,
                        p.precio
                      FROM ruta_productos rp
                      INNER JOIN productos p ON rp.producto_id = p.id
                      WHERE rp.ruta_id = :ruta_id";

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

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

    public function generarCodigoAutomatico()
    {
        try {
            $fecha = date('Ymd');
            $query = "SELECT codigo FROM rutas WHERE codigo LIKE :patron ORDER BY codigo DESC LIMIT 1";
            $stmt = $this->conn->prepare($query);
            $patron = "RT{$fecha}%";
            $stmt->bindParam(':patron', $patron);
            $stmt->execute();

            $ultimo = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($ultimo) {
                $numero = intval(substr($ultimo['codigo'], -3)) + 1;
            } else {
                $numero = 1;
            }

            return "RT{$fecha}" . str_pad($numero, 3, '0', STR_PAD_LEFT);

        } catch (Exception $e) {
            error_log("Error generando código automático: " . $e->getMessage());
            return "RT" . date('Ymd') . "001";
        }
    }

    public function registrarHistorial($rutaId, $usuarioId, $accion, $descripcion, $datosAdicionales = null)
    {
        try {
            $query = "INSERT INTO historial_rutas (ruta_id, usuario_id, accion, descripcion, datos_adicionales)
                      VALUES (:ruta_id, :usuario_id, :accion, :descripcion, :datos_adicionales)";

            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':ruta_id', $rutaId);
            $stmt->bindParam(':usuario_id', $usuarioId);
            $stmt->bindParam(':accion', $accion);
            $stmt->bindParam(':descripcion', $descripcion);
            $datosJson = $datosAdicionales ? json_encode($datosAdicionales) : null;
            $stmt->bindParam(':datos_adicionales', $datosJson);

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

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

            // Total de rutas
            $stmt = $this->conn->query("SELECT COUNT(*) as total FROM rutas");
            $estadisticas['total_rutas'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];

            // Rutas por estado
            $stmt = $this->conn->query("SELECT estado, COUNT(*) as cantidad FROM rutas GROUP BY estado");
            $estadisticas['por_estado'] = $stmt->fetchAll(PDO::FETCH_ASSOC);

            // Rutas de hoy
            $stmt = $this->conn->query("SELECT COUNT(*) as total FROM rutas WHERE fecha_ruta = CURDATE()");
            $estadisticas['rutas_hoy'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];

            // Rutas activas
            $stmt = $this->conn->query("SELECT COUNT(*) as total FROM rutas WHERE estado IN ('planificada', 'en_progreso')");
            $estadisticas['rutas_activas'] = $stmt->fetch(PDO::FETCH_ASSOC)['total'];

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

    public function obtenerRepartidoresDisponibles($fecha = null)
    {
        try {
            $fechaConsulta = $fecha ?? date('Y-m-d');

            // Obtener TODOS los repartidores activos, con información de cuántas rutas tienen asignadas
            $query = "SELECT
                        r.id,
                        r.codigo,
                        CONCAT(r.nombre, ' ', r.apellidos) as nombre_completo,
                        r.telefono,
                        (SELECT COUNT(*)
                         FROM rutas
                         WHERE repartidor_id = r.id
                         AND fecha_ruta = :fecha
                         AND estado IN ('planificada', 'en_progreso')) as rutas_asignadas
                      FROM repartidores r
                      WHERE r.activo = 1
                      ORDER BY rutas_asignadas ASC, r.nombre ASC";

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

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

    public function obtenerVehiculosDisponibles($fecha = null)
    {
        try {
            $fechaConsulta = $fecha ?? date('Y-m-d');
            
            $query = "SELECT v.id, v.codigo, v.marca, v.modelo, v.placa, v.tipo
                      FROM vehiculos v
                      WHERE v.activo = 1 
                      AND v.id NOT IN (
                          SELECT DISTINCT vehiculo_id 
                          FROM rutas 
                          WHERE fecha_ruta = :fecha 
                          AND estado IN ('planificada', 'en_progreso')
                          AND vehiculo_id IS NOT NULL
                      )
                      ORDER BY v.codigo";

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

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

    public function cambiarEstado($id, $nuevoEstado, $usuarioId)
    {
        try {
            $query = "UPDATE rutas SET estado = :estado WHERE id = :id";
            $stmt = $this->conn->prepare($query);
            $stmt->bindParam(':estado', $nuevoEstado);
            $stmt->bindParam(':id', $id);
            
            $result = $stmt->execute();

            if ($result) {
                $descripcion = "Estado cambiado a: $nuevoEstado";
                $this->registrarHistorial($id, $usuarioId, $nuevoEstado, $descripcion);
            }

            return $result;
        } catch (Exception $e) {
            error_log("Error cambiando estado de ruta: " . $e->getMessage());
            throw $e;
        }
    }
}
?>