import { ref } from 'vue'; import { useMapState } from './useMapState'; export interface Parada { id: number; nombre: string; latitud: number; longitud: number; orden: number; } export function useDirectionsRoute() { const estasCargando = ref(false); const errorRuta = ref(null); const { registrarPolyline, polylines } = useMapState(); // Limpia los tramos anteriores dibujados en el mapa const limpiarRuta = () => { if (polylines.value.length > 0) { polylines.value.forEach((polyline) => { polyline.setMap(null); }); polylines.value = []; } errorRuta.value = null; }; // Función utilitaria para pausar ejecución const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); const trazarRuta = async (paradas: Parada[], map: google.maps.Map, isPast: boolean = false) => { if (!paradas || paradas.length < 2) { errorRuta.value = 'Se requieren al menos 2 paradas para trazar una ruta.'; return; } // NOTA: No llamamos a limpiarRuta() aquí para poder encadenar llamadas (dibujar fondo + trazado activo) estasCargando.value = true; errorRuta.value = null; try { const { DirectionsService } = await google.maps.importLibrary("routes") as any; const directionsService = new DirectionsService(); const maxWaypoints = 23; // Google Directions limit is typically 25 including origin/dest for (let i = 0; i < paradas.length - 1; i += maxWaypoints) { const chunk = paradas.slice(i, i + maxWaypoints + 1); if (chunk.length < 2) break; const origin = { lat: chunk[0]!.latitud, lng: chunk[0]!.longitud }; const destination = { lat: chunk[chunk.length - 1]!.latitud, lng: chunk[chunk.length - 1]!.longitud }; const waypoints = chunk.slice(1, -1).map(p => ({ location: new google.maps.LatLng(p.latitud, p.longitud), stopover: true })); try { const result = await new Promise((resolve, reject) => { directionsService.route({ origin, destination, waypoints, travelMode: google.maps.TravelMode.DRIVING }, (response: google.maps.DirectionsResult | null, status: google.maps.DirectionsStatus) => { if (status === google.maps.DirectionsStatus.OK && response) { resolve(response); } else { reject(new Error(`Directions API failed: ${status}`)); } }); }); if (result.routes && result.routes.length > 0) { const route = result.routes[0]; if (route?.overview_path) { const polyline = new google.maps.Polyline({ path: route.overview_path, map: map, strokeColor: isPast ? '#9CA3AF' : '#FBBF24', strokeWeight: isPast ? 4 : 6, strokeOpacity: isPast ? 0.6 : 1.0, icons: isPast ? [{ icon: { path: 'M 0,-1 0,1', strokeOpacity: 1, scale: 2 }, offset: '0', repeat: '10px' }] : [] }); registrarPolyline(polyline); } } } catch (err: any) { console.warn(`SIBU | Tramo ${i} falló con Directions API: `, err); } if (i + maxWaypoints < paradas.length - 1) { await delay(300); } } } catch (err: any) { errorRuta.value = `Error crítico al trazar la ruta: ${err.message || String(err)}`; console.error(errorRuta.value); } finally { estasCargando.value = false; } }; return { trazarRuta, limpiarRuta, estasCargando, errorRuta }; }