/** Composable for Google Maps integration */
import { ref, shallowRef, onMounted } from 'vue'
import { setOptions, importLibrary } from '@googlemaps/js-api-loader'
import { useMapState } from './useMapState'

const getApiKey = () => import.meta.env.VITE_GOOGLE_MAPS_API_KEY || ''

let mapsLoaded = false

// Global overlay tracker - persists across all composable instances
const globalOverlays = new Map<google.maps.Map, Set<google.maps.Marker | google.maps.Polyline>>()

export function useGoogleMaps() {
    const map = shallowRef<google.maps.Map | null>(null)
    const isLoaded = ref(false)
    const error = ref<string | null>(null)
    const {
        registrarMarker,
        registrarPolyline,
        registrarCallbackLimpieza,
        limpiarMapa: limpiarTodoCentralizado
    } = useMapState()

    // Escuchar errores globales de autenticación de Google
    if (typeof window !== 'undefined') {
        (window as any).gm_auth_failure = () => {
            error.value = '⚠️ Error de Autenticación de Google: Revisa que la API de Mapas esté activada y que la facturación de Google Cloud sea válida.';
            console.error('❌ Google Maps Auth Failure detected');
        };
    }

    async function loadMaps() {
        if (mapsLoaded) {
            isLoaded.value = true
            error.value = null
            return
        }

        const apiKey = getApiKey()
        if (!apiKey || apiKey.length < 10) {
            error.value = '❌ Error: VITE_GOOGLE_MAPS_API_KEY no detectada o es inválida.'
            console.error(error.value)
            return
        }

        console.log('🌐 Usando Nueva API Funcional de Google Maps...');

        try {
            // Configuramos las opciones globales como pide el error
            setOptions({
                key: apiKey,
                v: 'weekly'
            });

            // Cargamos las librerías necesarias una por una
            console.log('🛰️ Cargando librerías...');
            await importLibrary('maps');
            await importLibrary('places');
            await importLibrary('geometry');
            await importLibrary('routes');

            if (typeof google === 'undefined' || !google.maps) {
                throw new Error('Google Maps se cargó pero el espacio de nombres "google.maps" no está disponible.');
            }

            mapsLoaded = true
            isLoaded.value = true
            error.value = null
            console.log('✅ Google Maps (New API) cargado con éxito');
        } catch (e: any) {
            console.error('❌ Error crítico en Nueva API:', e)

            let msg = 'Error de carga.'
            const errStr = String(e).toLowerCase()

            if (errStr.includes('apiprojectmaperror')) {
                msg = 'Error de Proyecto: API no habilitada o llave incorrecta.'
            } else if (errStr.includes('billing')) {
                msg = 'Facturación: Revisa tu cuenta en Google Cloud Console.'
            } else if (errStr.includes('referer') || errStr.includes('origin')) {
                msg = 'Restricción de Origen: La llave no permite peticiones desde esta App.'
            } else {
                msg = `Detalle: ${e.message || e}`
            }

            error.value = `⚠️ Google Maps: ${msg}`
        }
    }

    function initMap(
        containerId: string,
        center: { lat: number; lng: number },
        zoom: number = 12
    ) {
        if (!isLoaded.value) {
            console.error('Google Maps not loaded yet')
            return
        }

        const container = document.getElementById(containerId)
        if (!container) {
            console.error(`Map container with id "${containerId}" not found`)
            return
        }

        // Clear any existing overlays for this map before creating a new one
        if (map.value && globalOverlays.has(map.value)) {
            clearAllOverlaysForMap(map.value)
        }

        // 🚀 OPTIMIZACIÓN DE CUOTA: Si el mapa ya existe, no crearlo de nuevo (ahorra cargos de Map Load)
        if (map.value && container.contains(map.value.getDiv())) {
            console.log('SIBU | Mapa ya inicializado, reutilizando instancia...');
            map.value.setCenter(center);
            map.value.setZoom(zoom);
            return;
        }

        try {
            map.value = new google.maps.Map(container, {
                center,
                zoom,
                disableDefaultUI: true,
            })
        } catch (e: any) {
            console.error('❌ Error inicializando el objeto Map:', e);
            error.value = `Error de inicialización: ${e.message || e}`;
        }

        // Initialize overlay tracking for this map
        if (map.value && !globalOverlays.has(map.value)) {
            globalOverlays.set(map.value, new Set())
        }

        // Registrar callback para limpiar globalOverlays cuando useMapState.limpiarMapa() sea llamado
        registrarCallbackLimpieza(() => {
            if (map.value && globalOverlays.has(map.value)) {
                clearAllOverlaysForMap(map.value)
            }
        })
    }

    function addMarker(
        position: { lat: number; lng: number },
        options?: {
            title?: string
            draggable?: boolean
            icon?: google.maps.Icon | google.maps.Symbol | string
            onDragEnd?: (pos: { lat: number; lng: number }) => void
        }
    ): google.maps.Marker | null {
        if (!map.value) {
            console.error('Map not initialized')
            return null
        }

        const marker = new google.maps.Marker({
            position,
            map: map.value,
            title: options?.title,
            draggable: options?.draggable,
            icon: options?.icon,
        })

        registrarMarker(marker)

        if (options?.onDragEnd) {
            marker.addListener('dragend', () => {
                const pos = marker.getPosition()
                if (pos) {
                    options.onDragEnd!({ lat: pos.lat(), lng: pos.lng() })
                }
            })
        }

        // Track in global overlay tracker
        if (map.value) {
            if (!globalOverlays.has(map.value)) {
                globalOverlays.set(map.value, new Set())
            }
            globalOverlays.get(map.value)!.add(marker)
        }

        return marker
    }

    function addNumberedMarker(
        position: { lat: number; lng: number },
        number: number,
        title?: string,
        onClick?: () => void
    ): google.maps.Marker | null {
        if (!map.value) {
            console.error('Map not initialized')
            return null
        }

        // Note: google.maps.Marker is deprecated but still works
        // We'll keep using it for now as AdvancedMarkerElement requires additional setup
        // TODO: Migrate to google.maps.marker.AdvancedMarkerElement in the future
        const marker = new google.maps.Marker({
            position,
            map: map.value,
            title,
            icon: {
                path: google.maps.SymbolPath.CIRCLE,
                fillColor: '#FEE715', // Amarillo marca
                fillOpacity: 1,
                strokeColor: '#101820', // Negro marca
                strokeWeight: 2,
                scale: 14,
            },
            label: {
                text: number.toString(),
                color: '#101820',
                fontSize: '13px',
                fontWeight: '900',
            },
        })
        registrarMarker(marker)

        if (onClick) {
            marker.addListener('click', onClick)
        }

        // Track in global overlay tracker
        if (map.value) {
            if (!globalOverlays.has(map.value)) {
                globalOverlays.set(map.value, new Set())
            }
            globalOverlays.get(map.value)!.add(marker)
        }

        return marker
    }

    function addCleanMarker(
        position: { lat: number; lng: number },
        title: string,
        type: 'normal' | 'cercana' | 'origen' | 'destino' | 'pasada',
        onClick?: () => void
    ): google.maps.Marker | null {
        if (!map.value) {
            console.error('Map not initialized');
            return null;
        }

        const iconoParadaNormal = {
            path: google.maps.SymbolPath.CIRCLE,
            fillColor: '#FBBF24',       // amarillo
            fillOpacity: 1,
            strokeColor: '#FFFFFF',
            strokeWeight: 2,
            scale: 7
        };

        const iconoParadaCercana = {
            path: google.maps.SymbolPath.CIRCLE,
            fillColor: '#F59E0B',       // amarillo intenso
            fillOpacity: 1,
            strokeColor: '#FFFFFF',
            strokeWeight: 3,
            scale: 12
        };

        const iconoOrigen = {
            path: google.maps.SymbolPath.CIRCLE,
            fillColor: '#FBBF24',       // amarillo
            fillOpacity: 1,
            strokeColor: '#FFFFFF',
            strokeWeight: 3,
            scale: 10
        };

        const iconoDestino = {
            path: google.maps.SymbolPath.CIRCLE,
            fillColor: '#D97706',       // amarillo oscuro
            fillOpacity: 1,
            strokeColor: '#FFFFFF',
            strokeWeight: 3,
            scale: 10
        };

        const iconoParadaPasada = {
            path: google.maps.SymbolPath.CIRCLE,
            fillColor: '#FDE68A',       // amarillo tenue
            fillOpacity: 0.5,
            strokeColor: '#FFFFFF',
            strokeWeight: 1,
            scale: 5
        };

        const iconos = {
            normal: iconoParadaNormal,
            cercana: iconoParadaCercana,
            origen: iconoOrigen,
            destino: iconoDestino,
            pasada: iconoParadaPasada
        };

        const marker = new google.maps.Marker({
            position,
            map: map.value,
            title,
            icon: iconos[type],
        });
        registrarMarker(marker);

        if (onClick) {
            const infoWindow = new google.maps.InfoWindow({
                content: `
                  <div style="font-family: sans-serif; padding: 6px 10px; font-size: 13px; font-weight: 600; color: #1E3A5F; white-space: nowrap;">
                    🚌 ${title}
                  </div>
                `
            });
            marker.addListener('click', () => {
                infoWindow.open(map.value, marker);
                onClick();
            });
        }

        if (map.value) {
            if (!globalOverlays.has(map.value)) {
                globalOverlays.set(map.value, new Set());
            }
            globalOverlays.get(map.value)!.add(marker);
        }

        return marker;
    }

    function addHtmlMarker(
        position: { lat: number, lng: number },
        html: string,
        offset: { x: number, y: number } = { x: 0, y: 0 }
    ) {
        if (!map.value) return null;

        const overlay = new google.maps.OverlayView();
        let container: HTMLDivElement | null = null;

        overlay.onAdd = function () {
            container = document.createElement('div');
            container.style.position = 'absolute';
            container.innerHTML = html;
            const panes = this.getPanes();
            if (panes) panes.overlayMouseTarget.appendChild(container);
        };

        overlay.draw = function () {
            const projection = this.getProjection();
            if (!projection || !container) return;
            const pos = projection.fromLatLngToDivPixel(new google.maps.LatLng(position.lat, position.lng));
            if (pos) {
                container.style.left = (pos.x + offset.x) + 'px';
                container.style.top = (pos.y + offset.y) + 'px';
            }
        };

        overlay.onRemove = function () {
            if (container && container.parentNode) {
                container.parentNode.removeChild(container);
            }
            container = null;
        };

        overlay.setMap(map.value);
        registrarMarker(overlay as any);

        // Track in global overlay tracker
        if (!globalOverlays.has(map.value)) {
            globalOverlays.set(map.value, new Set());
        }
        globalOverlays.get(map.value)!.add(overlay as any);

        return overlay;
    }

    function addPolyline(path: Array<{ lat: number; lng: number }>): google.maps.Polyline | null {
        if (!map.value) {
            console.error('Map not initialized')
            return null
        }

        const polyline = new google.maps.Polyline({
            path,
            geodesic: true,
            strokeColor: '#101820', // Negro premium
            strokeOpacity: 0.8,
            strokeWeight: 5,
            map: map.value,
        })
        registrarPolyline(polyline)

        // Track in global overlay tracker
        if (map.value) {
            if (!globalOverlays.has(map.value)) {
                globalOverlays.set(map.value, new Set())
            }
            globalOverlays.get(map.value)!.add(polyline)
        }

        return polyline
    }

    async function addRoutePolyline(paradas: Array<{ lat: number; lng: number }>) {
        if (!map.value) {
            console.error('Map not initialized');
            return [];
        }
        if (!paradas || paradas.length < 2) {
            console.warn("Se necesitan al menos 2 paradas para trazar una ruta.");
            return [];
        }

        // Limpiar antes de dibujar una nueva ruta
        limpiarTodoCentralizado();
        if (map.value && globalOverlays.has(map.value)) {
            clearAllOverlaysForMap(map.value);
        }

        const polylinesCreadas: google.maps.Polyline[] = [];
        const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

        try {
            const { DirectionsService } = await google.maps.importLibrary("routes") as any;
            const directionsService = new DirectionsService();

            const tamañoChunk = 25;

            for (let i = 0; i < paradas.length - 1; i += (tamañoChunk - 1)) {
                const chunk = paradas.slice(i, i + tamañoChunk);
                if (chunk.length < 2) break;

                const origin = { lat: chunk[0]!.lat, lng: chunk[0]!.lng };
                const destination = { lat: chunk[chunk.length - 1]!.lat, lng: chunk[chunk.length - 1]!.lng };
                const waypoints = chunk.slice(1, -1).map(p => ({
                    location: new google.maps.LatLng(p.lat, p.lng),
                    stopover: true
                }));

                try {
                    const result = await new Promise<google.maps.DirectionsResult>((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.value,
                                strokeColor: '#FBBF24',
                                strokeWeight: 5,
                                strokeOpacity: 0.95,
                                geodesic: true
                            });

                            polylinesCreadas.push(polyline);
                            registrarPolyline(polyline);

                            if (!globalOverlays.has(map.value!)) {
                                globalOverlays.set(map.value!, new Set());
                            }
                            globalOverlays.get(map.value!)!.add(polyline);
                        }
                    }
                } catch (error) {
                    console.error(`Error trazando el tramo (Paradas ${i} a ${i + chunk.length}):`, error);
                }

                await delay(200);
            }
        } catch (e) {
            console.error('Error cargando Directions API:', e);
        }

        return polylinesCreadas;
    }

    function fitBounds(path: Array<{ lat: number; lng: number }>) {
        if (!map.value || path.length === 0) {
            return
        }

        const bounds = new google.maps.LatLngBounds()
        path.forEach((point) => {
            bounds.extend(new google.maps.LatLng(point.lat, point.lng))
        })
        map.value.fitBounds(bounds)
    }

    function setCenter(lat: number, lng: number) {
        if (map.value) {
            map.value.setCenter({ lat, lng })
        }
    }

    function setZoom(zoom: number) {
        if (map.value) {
            map.value.setZoom(zoom)
        }
    }

    function clearAllOverlays() {
        if (!map.value) {
            return
        }
        limpiarTodoCentralizado()
        clearAllOverlaysForMap(map.value)
    }

    function clearAllOverlaysForMap(targetMap: google.maps.Map) {
        const overlays = globalOverlays.get(targetMap)

        // Remove all tracked overlays from the map
        if (overlays) {
            const overlayCount = overlays.size
            overlays.forEach((overlay) => {
                if (overlay) {
                    try {
                        if ('setMap' in overlay && typeof overlay.setMap === 'function') {
                            overlay.setMap(null)
                        }
                        if ('remove' in overlay && typeof overlay.remove === 'function') {
                            overlay.remove()
                        }
                        if ('onRemove' in overlay && typeof overlay.onRemove === 'function') {
                            overlay.onRemove()
                        }
                    } catch (e) {
                        // Ignore errors when removing overlays
                        console.warn('Error removing overlay:', e)
                    }
                }
            })
            // Clear the set
            overlays.clear()
            console.log(`Cleared ${overlayCount} tracked overlays`)
        }

        // Manual DOM scraping fallback removed as it causes "removeChild" errors
        // with Google Maps' native OverlayView management.
    }

    onMounted(() => {
        loadMaps()
    })

    return {
        map,
        isLoaded,
        error,
        loadMaps,
        initMap,
        addMarker,
        addHtmlMarker,
        addNumberedMarker,
        addCleanMarker,
        addPolyline,
        addRoutePolyline,
        fitBounds,
        setCenter,
        setZoom,
        clearAllOverlays,
    }
}

