import { ref } from 'vue'
import { useMapState } from './useMapState'
import { useDirectionsRoute } from './useDirectionsRoute'
import { useParadaCercana } from './useParadaCercana'
import type { BusStop } from '@/types'
import { useRouteStore } from '@/stores/route'

export const useFlujoPrincipal = () => {
    const { limpiarMapa } = useMapState()
    const paradaCercanaInst = useParadaCercana()
    const { encontrarParadaCercana, paradaCercana } = paradaCercanaInst
    const { trazarRuta } = useDirectionsRoute()
    const cargando = ref(false)
    const errorMsg = ref('')

    // Simulated obtenerUbicacion (since it was just navigator.geolocation)
    const obtenerUbicacion = (): Promise<{ lat: number, lng: number }> => {
        return new Promise((resolve, reject) => {
            if (!navigator.geolocation) return reject(new Error('No geolocation'))
            navigator.geolocation.getCurrentPosition(
                (pos) => resolve({ lat: pos.coords.latitude, lng: pos.coords.longitude }),
                (err) => reject(err),
                { enableHighAccuracy: true, timeout: 8000, maximumAge: 30000 }
            )
        })
    }

    const procesarSeleccionDeRuta = async (
        _ruta: { id: string },
        paradasExistentes: BusStop[],
        map: google.maps.Map | undefined,
        addCleanMarker: Function,
        skipGuidedZoom = false,
        onStopClick?: (stop: BusStop) => void,
        cancelToken?: { cancelled: boolean }  // token de cancelación pasado desde el llamador
    ) => {
        if (!map) return

        try {
            // ── PASO 1: Inicio Atómico ──
            cargando.value = true
            limpiarMapa()
            const routeStore = useRouteStore()

            // ── PASO 2: Sincronización (Promise.all) ──
            // Disparamos Supabase (paradas) y GPS al mismo tiempo
            console.log('SIB | Iniciando carga síncrona de Datos + GPS...');

            const [ubicacionRes, paradasRes] = await Promise.allSettled([
                obtenerUbicacion(),
                paradasExistentes.length > 0 ? Promise.resolve(paradasExistentes) : routeStore.loadRouteStops(_ruta.id)
            ]);

            // Guard: abandono si el token fue cancelado o la ruta ya no está activa
            if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {
                console.log('SIB | procesarSeleccionDeRuta abortado tras Promise.allSettled (ruta ya no activa o cancelada)');
                limpiarMapa(); // limpiar cualquier polyline ya dibujada
                return;
            }

            // ── PASO 3: Asignación Segura ──
            let ubicacion: { lat: number, lng: number } | null = null;
            if (ubicacionRes.status === 'fulfilled') {
                ubicacion = ubicacionRes.value;
            } else {
                console.warn('SIB | GPS falló o fue denegado');
            }

            let paradas: BusStop[] = [];
            if (paradasRes.status === 'fulfilled') {
                // Si loadRouteStops no devolviera los datos directamente, los tomamos del store
                paradas = paradasRes.value || routeStore.selectedRouteStops;
            }

            const paradasFormateadas = paradas.map((p, i) => ({
                id: typeof p.id === 'string' ? parseInt(p.id) || i : p.id || i,
                nombre: p.name,
                latitud: p.latitude,
                longitud: p.longitude,
                orden: i
            }));

            if (paradasFormateadas.length < 2) {
                console.warn('SIB | No hay suficientes paradas para trazar ruta');
                return;
            }

            // Si no detectamos GPS, trazamos la ruta completa sin zoom guiado
            if (!ubicacion) {
                await trazarRuta(paradasFormateadas, map, false, cancelToken);
                if (cancelToken?.cancelled) { limpiarMapa(); return; }
                const bounds = new google.maps.LatLngBounds()
                paradasFormateadas.forEach(p => bounds.extend(new google.maps.LatLng(p.latitud, p.longitud)))
                map.fitBounds(bounds, { top: 100, bottom: 100, left: 60, right: 60 })
                return;
            }

            // ── PASO 4: Dibujar y Renderizar ──
            if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {
                limpiarMapa();
                return;
            }

            // Dibujar ruta completa (fondo)
            await trazarRuta(paradasFormateadas, map, true, cancelToken);

            if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {
                limpiarMapa(); // limpiar polylines ya dibujadas
                return;
            }

            if (skipGuidedZoom) {
                const bounds = new google.maps.LatLngBounds()
                paradasFormateadas.forEach(p => bounds.extend(new google.maps.LatLng(p.latitud, p.longitud)))
                map.fitBounds(bounds, { top: 100, bottom: 100, left: 60, right: 60 })
                return;
            }

            await encontrarParadaCercana(ubicacion, paradas, map, cancelToken)
            const paradaCercanaFound = paradaCercana.value

            if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {
                limpiarMapa();
                return;
            }
            if (!paradaCercanaFound) return;

            // Dibujar tramo relevante
            const idx = paradasFormateadas.findIndex(p => {
                const samePos = Math.abs(p.longitud - paradaCercanaFound.longitude) < 0.0001 &&
                    Math.abs(p.latitud - paradaCercanaFound.latitude) < 0.0001;
                return samePos || p.nombre === paradaCercanaFound.name;
            });

            if (idx !== -1) {
                const tramoRelevante = paradasFormateadas.slice(idx)
                if (tramoRelevante.length > 1) {
                    await trazarRuta(tramoRelevante, map, false, cancelToken)
                }
            }

            // Guard final antes de pintar markers
            if (cancelToken?.cancelled || routeStore.selectedRouteId !== _ruta.id) {
                limpiarMapa();
                return;
            }

            // Renderizado Condicional de Marcadores
            paradasFormateadas.forEach((p, i) => {
                const esCercana = i === idx;
                const esPasada = idx !== -1 && i < idx;

                addCleanMarker(
                    { lat: p.latitud, lng: p.longitud },
                    p.nombre,
                    esCercana ? 'cercana' : (esPasada ? 'pasada' : 'normal'),
                    () => {
                        if (onStopClick && paradas[i]) {
                            onStopClick(paradas[i]);
                        }
                    }
                );
            });

            hacerZoomAlTramoRelevante(ubicacion, paradaCercanaFound, map)

        } catch (error) {
            console.error('SIB | Error procesando ruta:', error)
            errorMsg.value = 'No se pudo cargar la ruta'
        } finally {
            // Apagar estado de carga
            cargando.value = false
        }
    }

    // ZOOM QUE MUESTRA USUARIO Y PARADA CERCANA:
    const hacerZoomAlTramoRelevante = (
        ubicacion: { lat: number, lng: number },
        paradaCercana: BusStop,
        map: google.maps.Map
    ) => {
        const bounds = new google.maps.LatLngBounds()

        // Incluir solo estos dos puntos clave
        bounds.extend(new google.maps.LatLng(ubicacion.lat, ubicacion.lng))
        bounds.extend(
            new google.maps.LatLng(paradaCercana.latitude, paradaCercana.longitude)
        )

        // Ajustar zoom con padding generoso para que se vean bien
        map.fitBounds(bounds, {
            top: 100,     // espacio para la navbar
            bottom: 200,  // espacio para el bottom sheet de ETA
            left: 60,
            right: 60
        })

        // Asegurar zoom mínimo para que se vea el contexto de la calle
        google.maps.event.addListenerOnce(
            map,
            'bounds_changed',
            () => {
                if ((map.getZoom() ?? 0) > 17) {
                    map.setZoom(17) // no acercar demasiado
                }
                if ((map.getZoom() ?? 0) < 14) {
                    map.setZoom(14) // no alejar demasiado
                }
            }
        )
    }

    return { procesarSeleccionDeRuta, cargando, errorMsg }
}
