import { useEffect, useRef, useState } from 'react';
import { useProjectLocations } from '../../hooks/useProjectData';
import VideoPreviewTooltip from './video-preview-tooltip';

interface GoogleMapsAPI {
    maps: {
        Map: new (element: HTMLElement, options: unknown) => GoogleMap;
        Marker: new (options: unknown) => GoogleMarker;
        InfoWindow: new (options?: unknown) => GoogleInfoWindow;
        SymbolPath: {
            CIRCLE: unknown;
        };
        Animation: {
            DROP: unknown;
            BOUNCE: unknown;
        };
        LatLngBounds: new () => GoogleLatLngBounds;
        event: {
            addListener: (instance: unknown, eventName: string, handler: () => void) => void;
        };
    };
}

interface GoogleMap {
    data: {
        loadGeoJson: (url: string) => void;
        setStyle: (style: unknown) => void;
        addListener: (event: string, callback: (event: GoogleDataFeatureEvent) => void) => void;
    };
    fitBounds: (bounds: GoogleLatLngBounds) => void;
    [key: string]: unknown;
}

interface GoogleMarker {
    setAnimation: (animation: unknown) => void;
    setIcon?: (icon: unknown) => void;
}

interface GoogleInfoWindow {
    open: (map: GoogleMap, marker: GoogleMarker) => void;
    close: () => void;
}

interface GoogleLatLngBounds {
    extend: (latlng: GoogleLatLng) => void;
}

interface GoogleLatLng {
    lat: () => number;
    lng: () => number;
}

interface GoogleDataFeatureEvent {
    feature: {
        getGeometry: () => {
            forEachLatLng: (callback: (latlng: GoogleLatLng) => void) => void;
        };
    };
}

interface InteractiveMapProps {
    className?: string;
    onProjectClick?: (projectId: number) => void;
}

// Intentionally avoid re-declaring `window.google` types here to prevent
// conflicts with other global declarations or included @types packages.

export default function InteractiveMap({ className = '', onProjectClick }: InteractiveMapProps) {
    const mapRef = useRef<HTMLDivElement>(null);
    const mapInstanceRef = useRef<GoogleMap | null>(null);
    const { locations: projectLocations } = useProjectLocations();
    const [isLoading, setIsLoading] = useState(true);
    const [isMapReady, setIsMapReady] = useState(false);

    // Video preview state
    const [hoveredProject, setHoveredProject] = useState<{
        title: string;
        thumbnail?: string;
        embedUrl?: string;
        isValid?: boolean;
        position: { x: number; y: number };
    } | null>(null);

    // Hook para saber cuándo el componente está montado en el DOM
    useEffect(() => {
        setIsMapReady(true);
        return () => {
            setIsMapReady(false);
        };
    }, []);

    useEffect(() => {
        const apiKey = import.meta.env.VITE_GOOGLE_MAPS_API_KEY;

        // console.log('Google Maps API Key:', apiKey ? 'Found' : 'Not found');

        if (!apiKey) {
            // console.warn('Google Maps API key not found');
            setIsLoading(false);
            return;
        }

        // Wait for component to be ready
        if (!isMapReady) {
            return;
        }

        // Early return if map is already initialized
        if (mapInstanceRef.current) {
            // console.log('Map already exists, skipping initialization');
            setIsLoading(false);
            return;
        }

        const initializeMap = () => {
            // console.log('Initializing map...', { hasMapRef: !!mapRef.current, hasGoogle: !!window.google, isMapReady });

            // Prevent multiple initializations
            if (mapInstanceRef.current) {
                // console.log('Map already initialized, skipping...');
                setIsLoading(false);
                return;
            }

            if (!mapRef.current) {
                // console.error('Map container not found');
                setIsLoading(false);
                return;
            }

            if (!window.google) {
                // console.error('Google Maps API not loaded');
                setIsLoading(false);
                return;
            }

            try {
                // Map styles
                const mapStyles: Array<{
                    featureType?: string;
                    elementType?: string;
                    stylers: Array<{ [key: string]: string | number }>;
                }> = [
                    //   {
                    //     "featureType": "all",
                    //     "elementType": "geometry",
                    //     "stylers": [{ "color": "#ffffff" }]
                    //   },
                    //   {
                    //     "featureType": "all",
                    //     "elementType": "labels.text.fill",
                    //     "stylers": [
                    //       { "gamma": 0.01 },
                    //       { "lightness": 20 },
                    //       { "color": "#10b981" }
                    //     ]
                    //   },
                    //   {
                    //     "featureType": "landscape",
                    //     "elementType": "geometry",
                    //     "stylers": [
                    //       { "lightness": 30 },
                    //       { "saturation": 30 },
                    //       { "color": "#f0fdf4" }
                    //     ]
                    //   },
                    //   {
                    //     "featureType": "water",
                    //     "elementType": "all",
                    //     "stylers": [
                    //       { "lightness": -20 },
                    //       { "color": "#a7f3d0" }
                    //     ]
                    //   }
                ];

                const map = new window.google.maps.Map(mapRef.current, {
                    zoom: 9,
                    center: { lat: 8.75111426934212, lng: -75.88054604758426 }, // Centro de Colombia
                    styles: mapStyles,
                    mapTypeId: 'terrain',
                    zoomControl: true,
                    mapTypeControl: false,
                    scaleControl: false,
                    streetViewControl: false,
                    rotateControl: false,
                    fullscreenControl: true,
                    gestureHandling: 'cooperative',
                });

                mapInstanceRef.current = map;

                // Cargar el archivo GeoJSON para resaltar Córdoba
                map.data.loadGeoJson('/assets/json/cordoba.geojson');

                // Estilo del polígono de Córdoba con resaltado de Montería
                map.data.setStyle(function (feature: any) {
                    const nombre = feature.getProperty('NOMBRE_ENT');
                    if (nombre === 'MONTERÍA') {
                        return {
                            fillColor: '#0066FF',
                            fillOpacity: 0.2,
                            strokeColor: '#003399',
                            strokeWeight: 1.2,
                        };
                    } else {
                        return {
                            fillColor: '#0066FF',
                            fillOpacity: 0.1,
                            strokeColor: '#003399',
                            strokeWeight: 0.4,
                        };
                    }
                });

                // Handle empty locations gracefully
                const hasRealLocations = Array.isArray(projectLocations) && projectLocations.length > 0;

                // Use real project locations if available, fallback to sample data for demo
                const locationsToUse = hasRealLocations
                    ? projectLocations
                    : [
                          { id: 1, lat: 4.711, lng: -74.0721, title: 'Proyecto Bogotá - Innovación Pedagógica', address: 'Bogotá, Colombia' },
                          { id: 2, lat: 6.2442, lng: -75.5812, title: 'Proyecto Medellín - Metodologías Activas', address: 'Medellín, Colombia' },
                          { id: 3, lat: 3.4516, lng: -76.532, title: 'Proyecto Cali - Educación Digital', address: 'Cali, Colombia' },
                          { id: 4, lat: 7.8939, lng: -72.5078, title: 'Proyecto Cúcuta - Collaborative Learning', address: 'Cúcuta, Colombia' },
                          { id: 5, lat: 10.9685, lng: -74.7813, title: 'Proyecto Barranquilla - STEAM Education', address: 'Barranquilla, Colombia' },
                      ];

                // console.log('Adding markers for', locationsToUse.length, 'locations', hasRealLocations ? '(real data)' : '(demo data)');

                // Group locations by coordinates to handle overlapping markers
                const locationGroups: { [key: string]: typeof locationsToUse } = {};
                locationsToUse.forEach((location) => {
                    const key = `${location.lat.toFixed(6)}_${location.lng.toFixed(6)}`;
                    if (!locationGroups[key]) {
                        locationGroups[key] = [];
                    }
                    locationGroups[key].push(location);
                });

                // Function to calculate offset for overlapping markers (spiral pattern)
                const calculateOffset = (index: number, total: number): { lat: number; lng: number } => {
                    if (total === 1 || index === 0) return { lat: 0, lng: 0 };
                    
                    const offsetDistance = 0.0003; // Approximately 30 meters
                    const angle = (2 * Math.PI * index) / (total - 1);
                    const spiralFactor = 1 + (index * 0.3); // Increase radius slightly for each marker
                    
                    return {
                        lat: offsetDistance * spiralFactor * Math.cos(angle),
                        lng: offsetDistance * spiralFactor * Math.sin(angle),
                    };
                };

                // Only add markers if we have locations
                if (locationsToUse.length > 0) {
                    let markerIndex = 0;
                    Object.values(locationGroups).forEach((group) => {
                        group.forEach((location, groupIndex) => {
                            const offset = calculateOffset(groupIndex, group.length);
                            const adjustedLat = location.lat + offset.lat;
                            const adjustedLng = location.lng + offset.lng;
                            
                            // Use different colors for overlapping markers
                            const markerColor = group.length > 1 
                                ? ['#10b981', '#3b82f6', '#f59e0b', '#ef4444', '#8b5cf6'][groupIndex % 5]
                                : '#10b981';
                            
                            const marker = new window.google.maps.Marker({
                                position: { lat: adjustedLat, lng: adjustedLng },
                                map: map,
                                title: location.title + (group.length > 1 ? ` (${groupIndex + 1}/${group.length} en esta ubicación)` : ''),
                                icon: {
                                    path: window.google.maps.SymbolPath.CIRCLE,
                                    scale: 10,
                                    fillColor: markerColor,
                                    fillOpacity: 0.9,
                                    strokeColor: '#ffffff',
                                    strokeWeight: 3,
                                },
                                animation: window.google.maps.Animation.DROP,
                                zIndex: 1000 - groupIndex, // Higher z-index for first markers
                            });

                        // Add click listener
                        window.google.maps.event.addListener(marker, 'click', () => {
                            if (onProjectClick) {
                                onProjectClick(location.id);
                            }
                        });

                        // Add hover effect - Type assertion needed for Google Maps API
                        const gmMarker = marker as typeof marker & { setIcon: (icon: unknown) => void };

                        window.google.maps.event.addListener(marker, 'mouseover', (event: { domEvent?: MouseEvent }) => {
                            gmMarker.setIcon({
                                path: window.google.maps.SymbolPath.CIRCLE,
                                scale: 12,
                                fillColor: '#059669',
                                fillOpacity: 1,
                                strokeColor: '#ffffff',
                                strokeWeight: 3,
                            });

                            // Show video preview if available
                            if (location.youtube?.is_valid) {
                                const mouseEvent = event.domEvent;
                                setHoveredProject({
                                    title: location.title,
                                    thumbnail: location.youtube.thumbnail || undefined,
                                    embedUrl: location.youtube.embed_url || undefined,
                                    isValid: location.youtube.is_valid,
                                    position: {
                                        x: mouseEvent?.clientX || 0,
                                        y: mouseEvent?.clientY || 0,
                                    },
                                });
                            }
                        });

                        window.google.maps.event.addListener(marker, 'mouseout', () => {
                            gmMarker.setIcon({
                                path: window.google.maps.SymbolPath.CIRCLE,
                                scale: 10,
                                fillColor: markerColor,
                                fillOpacity: 0.9,
                                strokeColor: '#ffffff',
                                strokeWeight: 3,
                            });

                            // Hide video preview
                            setHoveredProject(null);
                        });

                        // Bounce animation on load
                        setTimeout(() => {
                            marker.setAnimation(window.google.maps.Animation.BOUNCE);
                            setTimeout(() => {
                                marker.setAnimation(null);
                            }, 1400);
                        }, markerIndex * 200);
                        
                        markerIndex++;
                        });
                    });
                } else {
                    // console.log('No project locations available, map will show only base map');
                }

                // console.log('Map initialized successfully');
                setIsLoading(false);
            } catch (error) {
                // console.error('Error initializing map:', error);
                setIsLoading(false);
            }
        };

        // Use a stable global callback and a queue to avoid races where
        // the script calls a callback that has been deleted during unmount.
        const GLOBAL_INIT_FN = 'initInteractiveMap';

        // Ensure a queue exists on window for pending initializers
        const queueKey = '__interactiveMapReadyQueue';
        if (!(window as any)[queueKey]) {
            (window as any)[queueKey] = [] as Array<() => void>;
        }

        // Define the global callback once. When Google Maps loads it will call
        // `window.initInteractiveMap()` which drains the queue and runs all
        // pending initializers.
        if (!(window as any)[GLOBAL_INIT_FN]) {
            (window as any)[GLOBAL_INIT_FN] = () => {
                const q = (window as any)[queueKey] as Array<() => void>;
                // Drain the queue
                while (q && q.length) {
                    const fn = q.shift();
                    if (typeof fn === 'function') {
                        try {
                            fn();
                        } catch (err) {
                            console.error('Error running queued map initializer', err);
                        }
                    }
                }
            };
        }

        // Per-instance initializer wrapper that will be queued if the API isn't loaded yet
        const initializerWrapper = () => {
            requestAnimationFrame(() => {
                setTimeout(initializeMap, 50);
            });
        };
        let _retryAttempt = 0;
        const MAX_RETRIES = 1; // one retry with cache-bust

        const loadGoogleMaps = () => {
            if (window.google) {
                // Google Maps is already loaded, initialize directly
                if (mapRef.current && !mapInstanceRef.current) {
                    // Use requestAnimationFrame for better timing
                    requestAnimationFrame(() => {
                        setTimeout(initializeMap, 50);
                    });
                } else if (mapInstanceRef.current) {
                    setIsLoading(false);
                }
                return;
            }

            // Check if script is already being loaded
            const existingScript = document.querySelector(`script[src*="maps.googleapis.com"]`);
            if (existingScript) {
                // console.log('Google Maps script already loading...');
                // If API already available, initialize immediately
                if (window.google) {
                    initializerWrapper();
                    return;
                }

                // If the existing script uses a different callback than our stable one,
                // the API may call that old callback and never drain our queue. In that
                // case append a new script with our stable callback (mark it to avoid
                // duplicating later).
                try {
                    const src = (existingScript as HTMLScriptElement).src || '';
                    const hasOurCallback = src.includes(`callback=${GLOBAL_INIT_FN}`) || src.includes(`callback=${GLOBAL_INIT_FN}&`);
                    const isMarked = (existingScript as HTMLScriptElement).getAttribute('data-interactive-maps') === '1';

                    // console.log('Existing Google Maps script found:', { src, hasOurCallback, isMarked });

                    if (!hasOurCallback && !isMarked) {
                        // Append a new script that includes our callback. Mark it so we
                        // don't duplicate in future attempts.
                        const script = document.createElement('script');
                        script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&loading=async&callback=${GLOBAL_INIT_FN}`;
                        script.async = true;
                        script.defer = true;
                        script.setAttribute('data-interactive-maps', '1');
                        document.head.appendChild(script);

                        script.onerror = () => {
                            // console.error('Failed to load Google Maps API');
                            setIsLoading(false);
                        };
                        script.onload = () => {
                            if (window.google && typeof (window as any)[GLOBAL_INIT_FN] === 'function') {
                                try {
                                    (window as any)[GLOBAL_INIT_FN]();
                                } catch (err) {
                                    /* ignore */
                                }
                            }
                        };
                        (window as any)[queueKey].push(initializerWrapper);
                        return;
                    }
                } catch (err) {
                    // If anything goes wrong inspecting the existing script, fallback to
                    // queueing our initializer so it runs when the global callback runs.
                    // console.warn('Error while inspecting existing Google Maps script', err);
                }

                (window as any)[queueKey].push(initializerWrapper);
                return;
            }

            const script = document.createElement('script');
            // Use the stable global callback name so the script will call
            // `window.initInteractiveMap()` when finished loading
            script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&loading=async&callback=${GLOBAL_INIT_FN}`;
            script.async = true;
            script.defer = true;
            document.head.appendChild(script);

            script.onerror = () => {
                // console.error('Failed to load Google Maps API');
                setIsLoading(false);
            };
            // If script loads via onload (some environments) and the global callback
            // hasn't been called for some reason, ensure we drain the queue as a
            // fallback.
            script.onload = () => {
                // If the API is present but the global callback wasn't invoked by URL,
                // call it now to run queued initializers.
                if (window.google && typeof (window as any)[GLOBAL_INIT_FN] === 'function') {
                    try {
                        (window as any)[GLOBAL_INIT_FN]();
                    } catch (err) {
                        /* ignore */
                    }
                }
            };
        };

        loadGoogleMaps();

        // Timeout fallback - increased timeout for production
        const timeoutId = setTimeout(() => {
            if (!mapInstanceRef.current) {
                // console.warn('Google Maps loading timeout - no map instance created');

                // If there is an existing script but the API hasn't appeared, try a
                // one-time retry with a cache-busting param. This helps when a
                // previously-injected script didn't include our callback or a
                // transient network error occurred.
                const existingScript = document.querySelector(`script[src*="maps.googleapis.com"]`);
                if (existingScript && _retryAttempt < MAX_RETRIES) {
                    _retryAttempt += 1;
                    // console.log('Attempting one-time retry to load Google Maps API (cache-bust)');
                    const script = document.createElement('script');
                    const cacheBust = `cb=${Date.now()}`;
                    script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&loading=async&callback=${GLOBAL_INIT_FN}&${cacheBust}`;
                    script.async = true;
                    script.defer = true;
                    script.setAttribute('data-interactive-maps', '1');
                    document.head.appendChild(script);

                    script.onerror = () => {
                        // console.error('Retry failed to load Google Maps API');
                        setIsLoading(false);
                    };
                    script.onload = () => {
                        if (window.google && typeof (window as any)[GLOBAL_INIT_FN] === 'function') {
                            try {
                                (window as any)[GLOBAL_INIT_FN]();
                            } catch (err) {
                                /* ignore */
                            }
                        }
                    };

                    // Give the retry a shorter grace period
                    const retryTimeout = setTimeout(() => {
                        if (!mapInstanceRef.current) {
                            // console.warn('Google Maps retry timeout - still no map instance created');
                            setIsLoading(false);
                        }
                        clearTimeout(retryTimeout);
                    }, 10000);

                    return;
                }

                setIsLoading(false);
            }
        }, 15000); // Increased from 10s to 15s for slower connections

        return () => {
            // Cleanup and references
            clearTimeout(timeoutId);
            try {
                const q = (window as any)[queueKey] as Array<() => void> | undefined;
                if (q && q.length) {
                    // Remove our initializer wrapper from the queue if still present
                    const idx = q.indexOf(initializerWrapper as unknown as () => void);
                    if (idx !== -1) q.splice(idx, 1);
                }
            } catch (err) {
                // ignore
            }
            // Reset map instance to prevent re-initialization issues
            mapInstanceRef.current = null;
        };
    }, [projectLocations, onProjectClick, isMapReady]);

    const hasApiKey = !!import.meta.env.VITE_GOOGLE_MAPS_API_KEY;

    // Always render the map container so `mapRef` exists when the Google Maps
    // initializer runs. We display overlays for loading and for the missing-key
    // fallback to preserve the previous UX while preventing race conditions
    // where the API calls back before the container is mounted.
    return (
        <div className={`relative ${className}`}>
            <div
                ref={mapRef}
                className="h-full min-h-[500px] w-full overflow-hidden rounded-xl border border-emerald-200 shadow-lg dark:border-emerald-400/30"
            />

            {/* Loading overlay */}
            {isLoading && (
                <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
                    <div className="flex h-full min-h-[500px] w-full items-center justify-center rounded-xl bg-slate-100/90 dark:bg-slate-800/90">
                        <div className="text-emerald-600 dark:text-emerald-400">
                            <div className="h-8 w-8 animate-spin rounded-full border-b-2 border-emerald-600"></div>
                        </div>
                    </div>
                </div>
            )}

            {/* No API key fallback overlay */}
            {!hasApiKey && !isLoading && (
                <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
                    <div className="flex h-full min-h-[500px] w-full items-center justify-center rounded-xl border border-emerald-200 bg-gradient-to-br from-emerald-50 to-blue-50 dark:border-emerald-400/30 dark:from-emerald-900/20 dark:to-blue-900/20">
                        <div className="p-8 text-center">
                            <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-emerald-100 dark:bg-emerald-800">
                                <span className="text-2xl">🗺️</span>
                            </div>
                            <h3 className="mb-2 text-xl font-semibold text-emerald-700 dark:text-emerald-400">Mapa de Proyectos</h3>
                            <p className="mb-4 text-slate-600 dark:text-slate-300">
                                Aquí se mostraría el mapa interactivo con todos los proyectos de Colombia
                            </p>
                            <div className="text-sm text-slate-500 dark:text-slate-400">
                                <p>📍 {projectLocations.length || 5} proyectos disponibles</p>
                                <p>🏛️ Instituciones educativas</p>
                                <p>🔬 Innovación pedagógica</p>
                            </div>
                        </div>
                    </div>
                </div>
            )}

            {/* Video Preview Tooltip */}
            {hoveredProject && (
                <VideoPreviewTooltip
                    title={hoveredProject.title}
                    thumbnail={hoveredProject.thumbnail}
                    embedUrl={hoveredProject.embedUrl}
                    isValid={hoveredProject.isValid}
                    position={hoveredProject.position}
                    visible={true}
                />
            )}
        </div>
    );
}
