import React, { useEffect, useRef, useState } from 'react';
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import ArrowIcon from './ArrowIcon';
import ReactDOM from 'react-dom/client';

interface MinimapProps {
  lat: number;
  lng: number;
  yaw?: number; // in radians
  heading?: number; // in degrees
  endLat?: number;
  endLng?: number;
  cityId?: string;
}

mapboxgl.accessToken = process.env.NEXT_PUBLIC_MAPBOX_TOKEN || '';

const Minimap: React.FC<MinimapProps> = ({ lat, lng, yaw = 0, heading = 0, endLat, endLng, cityId }) => {
  const mapContainer = useRef<HTMLDivElement>(null);
  const mapRef = useRef<mapboxgl.Map | null>(null);
  
  const markerRef = useRef<mapboxgl.Marker | null>(null);
  const markerDivRef = useRef<HTMLDivElement | null>(null);
  const markerArrowRootRef = useRef<ReturnType<typeof ReactDOM.createRoot> | null>(null);

  const endMarkerRef = useRef<mapboxgl.Marker | null>(null);
  const endMarkerDivRef = useRef<HTMLDivElement | null>(null);
  const endMarkerArrowRootRef = useRef<ReturnType<typeof ReactDOM.createRoot> | null>(null);
  
  const [hovered, setHovered] = useState(false);
  const prevYawRef = useRef<number>(yaw);
  const totalRotationRef = useRef<number>(0);
  const initialZoomSetRef = useRef<boolean>(false);
  const prevHoveredRef = useRef<boolean>(false);

  // Initial map creation
  useEffect(() => {
    if (!mapContainer.current) return;

    if (mapRef.current) {
      mapRef.current.remove();
      mapRef.current = null;
    }

    const map = new mapboxgl.Map({
      container: mapContainer.current,
      style: 'mapbox://styles/mapbox/streets-v11',
      center: [lng, lat],
      zoom: 13,
      interactive: false,
      bearing: 0,
    });

    map.on('load', () => {
      map.loadImage('https://axukvwsddnrihsfilobo.supabase.co/storage/v1/object/public/goquest//bus.png', (error, image) => {
        if (error) throw error;
        if (!map.hasImage('bus-pin')) {
          map.addImage('bus-pin', image!);
        }
      });
      
      map.addSource('public-transport-stops', {
        type: 'geojson',
        data: `https://axukvwsddnrihsfilobo.supabase.co/storage/v1/object/public/goquest//${cityId}.geojson`,
        cluster: true,
        clusterRadius: 50,
      });
    
      map.addLayer({
        id: 'transport-stops-layer',
        type: 'symbol',
        source: 'public-transport-stops',
        minzoom: 14,
        layout: {
          'icon-image': 'bus-pin',
          'icon-size': 0.12,
          'icon-allow-overlap': false
        }      
      });

      // Set initial zoom and center only once when map loads
      if (!initialZoomSetRef.current && endLat && endLng) {
        const bounds = new mapboxgl.LngLatBounds(
          [Math.min(lng, endLng), Math.min(lat, endLat)],
          [Math.max(lng, endLng), Math.max(lat, endLat)]
        );
        map.fitBounds(bounds, {
          padding: 50,
          maxZoom: 15
        });
        initialZoomSetRef.current = true;
      }
    });

    mapRef.current = map;

    const newMarkerDiv = document.createElement('div');
    newMarkerDiv.style.width = '32px';
    newMarkerDiv.style.height = '32px';
    newMarkerDiv.style.position = 'relative';
    newMarkerDiv.style.display = 'flex';
    newMarkerDiv.style.alignItems = 'center';
    newMarkerDiv.style.justifyContent = 'center';
    newMarkerDiv.innerHTML = '';
    
    const arrowContainer = document.createElement('div');
    arrowContainer.style.position = 'absolute';
    arrowContainer.style.top = '4px';
    arrowContainer.style.left = '4px';
    arrowContainer.style.zIndex = '2';
    arrowContainer.style.pointerEvents = 'none';
    arrowContainer.style.transition = 'transform 0.2s ease';
    arrowContainer.style.display = 'block';
    arrowContainer.id = 'minimap-arrow';
    newMarkerDiv.appendChild(arrowContainer);
    
    if (markerArrowRootRef.current) {
        const rootToUnmount = markerArrowRootRef.current;
        queueMicrotask(() => {
            rootToUnmount.unmount();
        });
    }
    markerArrowRootRef.current = ReactDOM.createRoot(arrowContainer);
    markerArrowRootRef.current.render(<ArrowIcon color="green"/>);
    
    markerDivRef.current = newMarkerDiv;
    const newMarker = new mapboxgl.Marker({
        element: newMarkerDiv,
        anchor: 'bottom',
        scale: 1
    })
      .setLngLat([lng, lat])
      .addTo(map);
    markerRef.current = newMarker;

    return () => {
      if (markerArrowRootRef.current) {
        const rootToUnmount = markerArrowRootRef.current;
        queueMicrotask(() => {
          rootToUnmount.unmount();
        });
        markerArrowRootRef.current = null;
      }
      if (markerRef.current) {
        markerRef.current.remove();
        markerRef.current = null;
      }
      if (mapRef.current) {
        mapRef.current.remove();
        mapRef.current = null;
      }
      if (mapContainer.current) {
        mapContainer.current.innerHTML = '';
      }
    };
  }, []); // Empty dependency array: map is created once per component instance.

  // Add end point marker when coordinates are available
  useEffect(() => {
    const currentMap = mapRef.current;
    if (!currentMap || !endLat || !endLng) {
      if (endMarkerRef.current) {
        if (endMarkerArrowRootRef.current) {
          const rootToUnmount = endMarkerArrowRootRef.current;
          queueMicrotask(() => {
            rootToUnmount.unmount();
          });
          endMarkerArrowRootRef.current = null;
        }
        endMarkerRef.current.remove();
        endMarkerRef.current = null;
      }
      return;
    }

    if (endMarkerRef.current) {
      if (endMarkerArrowRootRef.current) {
        const rootToUnmount = endMarkerArrowRootRef.current;
        queueMicrotask(() => {
          rootToUnmount.unmount();
        });
        endMarkerArrowRootRef.current = null;
      }
      endMarkerRef.current.remove();
      endMarkerRef.current = null;
    }

    const newEndMarkerDiv = document.createElement('div');
    newEndMarkerDiv.style.width = '32px';
    newEndMarkerDiv.style.height = '32px';
    newEndMarkerDiv.style.display = 'flex';
    newEndMarkerDiv.style.alignItems = 'center';
    newEndMarkerDiv.style.justifyContent = 'center';
    newEndMarkerDiv.innerHTML = '';
    
    const endArrowContainer = document.createElement('div');
    endArrowContainer.style.position = 'absolute';
    endArrowContainer.style.top = '4px';
    endArrowContainer.style.left = '4px';
    endArrowContainer.style.zIndex = '2';
    endArrowContainer.style.pointerEvents = 'none';
    endArrowContainer.style.transition = 'transform 0.2s ease';
    endArrowContainer.style.display = 'block';
    endArrowContainer.id = 'minimap-end-arrow';
    newEndMarkerDiv.appendChild(endArrowContainer);
    
    if (endMarkerArrowRootRef.current) {
        const rootToUnmount = endMarkerArrowRootRef.current;
        queueMicrotask(() => {
            rootToUnmount.unmount();
        });
    }
    endMarkerArrowRootRef.current = ReactDOM.createRoot(endArrowContainer);
    endMarkerArrowRootRef.current.render(<ArrowIcon color="red" />);
    
    endMarkerDivRef.current = newEndMarkerDiv;
    const newEndMarker = new mapboxgl.Marker({
        element: newEndMarkerDiv,
        anchor: 'bottom',
        scale: 1
    })
      .setLngLat([endLng, endLat])
      .addTo(currentMap);
    endMarkerRef.current = newEndMarker;

    return () => {
      if (endMarkerArrowRootRef.current) {
        const rootToUnmount = endMarkerArrowRootRef.current;
        queueMicrotask(() => {
          rootToUnmount.unmount();
        });
        endMarkerArrowRootRef.current = null;
      }
      if (endMarkerRef.current) {
        endMarkerRef.current.remove();
        endMarkerRef.current = null;
      }
    };
  }, [endLat, endLng]);

  // Update marker position and center map when lat/lng changes
  useEffect(() => {
    if (!mapRef.current || !markerRef.current) return;
    
    // Update marker position
    markerRef.current.setLngLat([lng, lat]);
    
    // Center map on current position
    mapRef.current.setCenter([lng, lat]);
    mapRef.current.setZoom(15);
    
    const delta = yaw - prevYawRef.current;
    if (delta > Math.PI) {
      totalRotationRef.current -= 2 * Math.PI;
    } else if (delta < -Math.PI) {
      totalRotationRef.current += 2 * Math.PI;
    }
    totalRotationRef.current += delta;
    prevYawRef.current = yaw;

    const arrow = markerDivRef.current?.querySelector<SVGElement>('#minimap-arrow');
    if (arrow) {
      arrow.style.transform = 'none';
    }
  }, [lat, lng, yaw]);

  // Handle hover state for interactivity
  useEffect(() => {
    if (!mapRef.current) return;
    let rafId: number | null = null;
    const resizeLoop = () => {
      if (mapRef.current) {
        mapRef.current.resize();
      }
      if (hovered) {
        rafId = requestAnimationFrame(resizeLoop);
      }
    };
    
    // Check if we're transitioning from hovered to non-hovered
    if (prevHoveredRef.current && !hovered) {
      // When map shrinks, center the map on the current position
      if (mapRef.current) {
        mapRef.current.setCenter([lng, lat]);
      }
    }
    
    if (hovered) {
      mapRef.current["scrollZoom"].enable();
      mapRef.current["dragPan"].enable();
      resizeLoop();
    } else {
      mapRef.current["scrollZoom"].disable();
      mapRef.current["dragPan"].disable();
      mapRef.current.resize();
    }
    
    // Update previous hovered state for next render
    prevHoveredRef.current = hovered;
    
    return () => {
      if (rafId) cancelAnimationFrame(rafId);
    };
  }, [hovered, lat, lng]);

  return (
    <div
      ref={mapContainer}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      style={{
        position: 'fixed',
        bottom: 24,
        right: 24,
        width: hovered ? 600 : 300,
        height: hovered ? 600 : 300,
        borderRadius: 16,
        overflow: 'hidden',
        boxShadow: '0 2px 8px rgba(0,0,0,0.15)',
        zIndex: 1000,
        border: '2px solid #fff',
        transition: 'width 0.25s cubic-bezier(.4,2,.6,1), height 0.25s cubic-bezier(.4,2,.6,1)',
        cursor: hovered ? 'grab' : 'pointer',
      }}
    />
  );
};

export default Minimap; 