import { useCallback, useState } from "react";
import React, { useRef, useEffect, Dispatch, SetStateAction } from "react";
import mapboxgl, { LngLatBounds } from "mapbox-gl";
import "mapbox-gl/dist/mapbox-gl.css";
import { GiObservatory } from "react-icons/gi";
import Event from "@appTypes/Event";
import getMagnitudeColor from "@utils/getMagnitudeColour";

interface MapComponentProps {
  events: Event[];
  selectedEventId: Event["id"];
  setSelectedEventId: Dispatch<SetStateAction<string>>;
  hoveredEventId: Event["id"];
  setHoveredEventId: Dispatch<SetStateAction<string>>;
}

// Map component with location-style pulsing dots, animations, and tooltips
function MapComponent({ events, selectedEventId, setSelectedEventId, hoveredEventId, setHoveredEventId }: MapComponentProps) {
  const map = useRef<mapboxgl.Map | null>(null);
  const markers = useRef<{ [key: string]: mapboxgl.Marker }>({});
  const [mapBounds, setMapBounds] = useState<LngLatBounds>();

  const fitToBounds = useCallback((bounds: LngLatBounds) => {
    if (map.current && bounds) {
      map.current!.fitBounds(bounds, { padding: 150, maxZoom: 10 });
    }
  }, []);

  const showPopup = useCallback((eventId: string) => {
    const marker = markers.current[eventId];
    if (marker && map.current) {
      marker.getPopup()?.addTo(map.current);
    }
  }, []);

  const clearAllPopups = useCallback(() => {
    Object.values(markers.current).forEach((marker) => marker.getPopup()?.remove());
  }, []);

  const flyToEvent = useCallback((event: Event) => {
    if (map.current) {
      map.current.flyTo({
        center: [event.longitude, event.latitude],
        zoom: 4,
        speed: 1.5,
        curve: 1.42,
      });
    }
  }, []);

  useEffect(() => {
    mapboxgl.accessToken = "pk.eyJ1IjoidGltaG93aXR6IiwiYSI6ImNtOGtjcXA5bDA3Ym4ya3NnOWxjbjlxZG8ifQ.6u_KgXEdLTakz910QRAorQ";

    try {
      map.current = new mapboxgl.Map({
        container: "map-container",
        style: "mapbox://styles/mapbox/light-v10",
        center: [0, 0],
        zoom: 1,
      });
    } catch (error) {
      console.error("Map initialization failed:", error);
      return;
    }

    map.current.on("load", () => {
      // Fit map to bounds
      const bounds = new mapboxgl.LngLatBounds();
      events.forEach((event) => {
        bounds.extend([event.longitude, event.latitude]);
      });
      fitToBounds(bounds);
      setMapBounds(bounds);

      // Add markers with location pulse
      events.forEach((event) => {
        const color = getMagnitudeColor(event.magnitude);

        //<GiObservatory />

        // Create marker container
        const markerElement = document.createElement("div");
        markerElement.style.width = "50px"; // Increased size to accommodate pulse
        markerElement.style.height = "50px";
        markerElement.style.position = "absolute";
        markerElement.style.display = "flex";
        markerElement.style.alignItems = "center";
        markerElement.style.justifyContent = "center";

        // Central dot
        const dotElement = document.createElement("div");
        dotElement.style.width = "10px";
        dotElement.style.height = "10px";
        dotElement.style.backgroundColor = color;
        dotElement.style.borderRadius = "50%";
        dotElement.style.position = "absolute";
        dotElement.style.zIndex = "2"; // Ensure dot is above pulse

        // Pulsing ring
        const pulseElement = document.createElement("div");
        pulseElement.className = "location-pulse";
        pulseElement.style.width = "20px"; // Initial size
        pulseElement.style.height = "20px";
        pulseElement.style.backgroundColor = `${color}80`; // Color with 50% opacity (hex alpha)
        pulseElement.style.borderRadius = "50%";
        pulseElement.style.position = "absolute";
        pulseElement.style.zIndex = "1";

        markerElement.appendChild(pulseElement);
        markerElement.appendChild(dotElement);

        const marker = new mapboxgl.Marker({ element: markerElement }).setLngLat([event.longitude, event.latitude]).addTo(map.current!);

        const popup = new mapboxgl.Popup({ offset: 25, closeButton: false, anchor: "bottom" }).setHTML(`
          <div>
            <h3>${event.title}</h3>
            <p>Magnitude: ${event.magnitude}</p>
            <p>${event.text2}</p>
          </div>
        `);

        marker.setPopup(popup);
        markers.current[event.id] = marker;

        // Add hover events
        const markerDomElement = marker.getElement();
        markerDomElement.style.cursor = "pointer"; // Optional: indicate interactivity

        markerDomElement.addEventListener("mouseenter", () => setHoveredEventId(event.id));
        markerDomElement.addEventListener("mouseleave", () => setHoveredEventId(""));
        markerDomElement.addEventListener("click", () => setSelectedEventId((prevEventId) => (prevEventId === event.id ? "" : event.id)));

        // Cleanup event listeners on unmount
        markerDomElement.dataset.listenersAdded = "true"; // Mark for cleanup
      });
    });

    map.current.on("error", (e) => {
      console.error("Mapbox error:", e);
    });

    return () => {
      map.current?.remove();
    };
  }, [events, setSelectedEventId, setHoveredEventId, fitToBounds]);

  useEffect(() => {
    const event = events.find((x) => x.id === selectedEventId);
    if (event) flyToEvent(event);
    else if (!selectedEventId) {
      if (mapBounds) fitToBounds(mapBounds);
    }
  }, [events, selectedEventId, mapBounds, fitToBounds, clearAllPopups, flyToEvent]);

  useEffect(() => {
    // Clear all popups first
    clearAllPopups();

    // Handle both events if they exist and are different
    if (hoveredEventId && selectedEventId && hoveredEventId !== selectedEventId) {
      showPopup(hoveredEventId);
      showPopup(selectedEventId);
    }
    // Handle single event case (either hovered or selected)
    else if (hoveredEventId || selectedEventId) {
      showPopup(hoveredEventId || selectedEventId);
    }
  }, [hoveredEventId, selectedEventId, clearAllPopups, showPopup]);

  return (
    <div className="w-full h-full">
      <div id="map-container" className="w-full h-full" />
    </div>
  );
}

// CSS for location-style pulsing animation
const pulseStyles = `
  .location-pulse {
    animation: locationPulse 2s infinite;
  }

  @keyframes locationPulse {
    0% {
      transform: scale(0.5);
      opacity: 0.8;
    }
    70% {
      transform: scale(2);
      opacity: 0;
    }
    100% {
      transform: scale(2);
      opacity: 0;
    }
  }
`;

export default function Map(props: MapComponentProps) {
  return (
    <>
      <style>{pulseStyles}</style>
      <MapComponent {...props} />
    </>
  );
}
