import React, { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { MapContainer, TileLayer, Marker, Polyline, Popup, useMap, useMapEvents } from 'react-leaflet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { ChevronLeft, Compass } from 'lucide-react';

interface NavigationRouteData {
  origin: { lat: number; lng: number };
  destination: { lat: number; lng: number; name: string };
  tourTitle?: string;
}

interface TourNavigationPageProps {
  tourId: string;
  routeData: NavigationRouteData | null;
  onBack: () => void;
}

const FitBounds = ({ coords, destination, hasInteractedRef }: { coords: [number, number][], destination: { lat: number; lng: number; name: string } | null, hasInteractedRef: React.MutableRefObject<boolean> }) => {
  const map = useMap();
  useEffect(() => {
    if (coords.length > 0 && !hasInteractedRef.current && destination) {
      map.fitBounds(coords, { padding: [60, 60], maxZoom: 15 });
    }
  }, [map, coords, destination, hasInteractedRef]);
  return null;
};

const MapRotationHandler = ({ rotation }: { rotation: number }) => {
  const map = useMap();
  const cumulativeRotationRef = useRef(0);
  const prevRotationRef = useRef(0);

  useEffect(() => {
    const container = map.getContainer();
    container.style.transformOrigin = 'center center';
    container.style.willChange = 'transform';

    if (rotation === 0) {
      cumulativeRotationRef.current = 0;
      prevRotationRef.current = 0;
      container.style.transform = '';
      return;
    }

    let delta = rotation - prevRotationRef.current;
    if (delta > 180) delta -= 360;
    else if (delta < -180) delta += 360;

    cumulativeRotationRef.current += delta;
    prevRotationRef.current = rotation;

    container.style.transform = `rotate(${cumulativeRotationRef.current}deg) scale(2.2) translateZ(0)`;
    container.style.transition = 'transform 0.2s cubic-bezier(0.25, 0.1, 0.25, 1)';
  }, [rotation, map]);
  return null;
};

const CompassInteractionDetector = ({
  onUserInteraction,
  hasInteractedRef
}: {
  onUserInteraction: () => void;
  hasInteractedRef: React.MutableRefObject<boolean>;
}) => {
  useMapEvents({
    movestart: () => { hasInteractedRef.current = true; },
    zoomstart: () => { hasInteractedRef.current = true; },
    dragstart: () => { hasInteractedRef.current = true; },
  });
  return null;
};

const MapRefSetter = ({ mapRef }: { mapRef: React.MutableRefObject<L.Map | null> }) => {
  const map = useMap();
  useEffect(() => {
    mapRef.current = map;
  }, [map, mapRef]);
  return null;
};

const MapInteractionWatcher = ({ hasInteractedRef }: { hasInteractedRef: React.MutableRefObject<boolean> }) => {
  const map = useMap();
  useEffect(() => {
    const onZoomEnd = () => {
      map._userZoomLevel = map.getZoom();
      hasInteractedRef.current = true;
    };
    const onMoveEnd = () => {
      map._userCenter = map.getCenter();
      hasInteractedRef.current = true;
    };
    map.on('zoomend', onZoomEnd);
    map.on('moveend', onMoveEnd);
    return () => {
      map.off('zoomend', onZoomEnd);
      map.off('moveend', onMoveEnd);
    };
  }, [map, hasInteractedRef]);
  return null;
};

const MapSizeHandler = ({ mapRef }: { mapRef: React.MutableRefObject<L.Map | null> }) => {
  const map = useMap();
  const prevSizeRef = useRef<{ width: number; height: number } | null>(null);

  useEffect(() => {
    const container = map.getContainer();
    if (!container) return;

    prevSizeRef.current = { width: container.clientWidth, height: container.clientHeight };

    const observer = new ResizeObserver(() => {
      const newWidth = container.clientWidth;
      const newHeight = container.clientHeight;
      const prev = prevSizeRef.current;

      if ((prev && (Math.abs(newWidth - prev.width) > 2 || Math.abs(newHeight - prev.height) > 2)) || newWidth === 0 || newHeight === 0) {
        prevSizeRef.current = { width: newWidth, height: newHeight };
        const userZoom = (map as any)._userZoomLevel as number | undefined;
        
        map.invalidateSize({ animate: false });
        
        if (userZoom !== undefined && Math.abs(map.getZoom() - userZoom) > 0.01) {
          map.setZoom(userZoom, { animate: false });
        }
      }
    });

    observer.observe(container);
    return () => observer.disconnect();
  }, [map, mapRef]);

  return null;
};

export const TourNavigationPage: React.FC<TourNavigationPageProps> = ({ tourId, routeData, onBack }) => {
  const [isCompassActive, setIsCompassActive] = useState(false);
  const [isLocatingUser, setIsLocatingUser] = useState(false);
  const [currentHeading, setCurrentHeading] = useState(0);
  const [routeGeometry, setRouteGeometry] = useState<[number, number][] | null>(null);
  const [error, setError] = useState<string | null>(null);

  const mapRef = useRef<L.Map | null>(null);
  const watchIdRef = useRef<number | null>(null);
  const fetchLockRef = useRef(false);
  const hasInteractedRef = useRef(false);

  const originLat = routeData?.origin?.lat;
  const originLng = routeData?.origin?.lng;
  const destLat = routeData?.destination?.lat;
  const destLng = routeData?.destination?.lng;

  const stopLocating = useCallback(() => {
    setIsLocatingUser(false);
  }, []);

  useEffect(() => {
    const map = mapRef.current;
    if (!map) return;

    const onMoveStart = () => {
      if (isLocatingUser) {
        stopLocating();
      }
    };
    map.on('movestart', onMoveStart);
    return () => {
      map.off('movestart', onMoveStart);
    };
  }, [isLocatingUser, stopLocating]);

  useEffect(() => {
    if (!isLocatingUser || !mapRef.current) return;

    if (navigator.geolocation) {
      watchIdRef.current = navigator.geolocation.watchPosition(
        (position) => {
          if (mapRef.current) {
            const currentZoom = mapRef.current.getZoom();
            mapRef.current.setView([position.coords.latitude, position.coords.longitude], currentZoom, { animate: true });
          }
        },
        (err) => console.error("User location tracking error:", err),
        { enableHighAccuracy: true }
      );
    }

    return () => {
      if (watchIdRef.current !== null) {
        navigator.geolocation.clearWatch(watchIdRef.current);
        watchIdRef.current = null;
      }
    };
  }, [isLocatingUser]);

  useEffect(() => {
    if (!routeData || !originLat || !originLng || !destLat || !destLng) {
      setRouteGeometry(null);
      setError(null);
      return;
    }

    if (fetchLockRef.current) return;

    const calculateOptimalRoute = async () => {
      try {
        fetchLockRef.current = true;
        const url = `https://router.project-osrm.org/route/v1/driving/${originLng},${originLat};${destLng},${destLat}?overview=full&geometries=geojson`;
        const res = await fetch(url);
        if (!res.ok) throw new Error(`OSRM error: ${res.status}`);
        const data: { code: string; routes: Array<{ geometry: { coordinates: number[][] } }> } = await res.json();
        if (data.code !== 'Ok' || !data.routes?.length) throw new Error('Không tìm thấy lộ trình phù hợp');

        const coords = data.routes[0].geometry.coordinates.map((c: number[]) => [c[1], c[0]] as [number, number]);
        setRouteGeometry(coords);
      } catch (err: any) {
        setError(err.message);
      } finally {
        fetchLockRef.current = false;
      }
    };

    calculateOptimalRoute();

    return () => {
      fetchLockRef.current = false;
    };
  }, [routeData, originLat, originLng, destLat, destLng]);

  const handleUserInteraction = useCallback(() => {
    hasInteractedRef.current = true;
    if (isCompassActive) {
      setIsCompassActive(false);
    }
  }, [isCompassActive]);

  useEffect(() => {
    if (!isCompassActive) {
      setCurrentHeading(0);
      return;
    }

    if (navigator.geolocation) {
      watchIdRef.current = navigator.geolocation.watchPosition(
        (position) => {
          if (mapRef.current) {
            mapRef.current.setView([position.coords.latitude, position.coords.longitude], undefined, { animate: true });
          }
          if (position.coords.heading !== null) {
            setCurrentHeading(position.coords.heading);
          }
        },
        (err) => console.error("Compass tracking acquisition error:", err),
        { enableHighAccuracy: true }
      );
    }

    const handleOrientation = (event: any) => {
      let heading: number | null = null;
      if (event.webkitCompassHeading !== undefined && event.webkitCompassHeading !== null) {
        heading = event.webkitCompassHeading;
      } else if (event.alpha !== null && event.alpha !== undefined) {
        if (event.absolute === true || event.type === 'deviceorientationabsolute') {
          heading = (360 - event.alpha) % 360;
        }
      }
      if (heading !== null) {
        setCurrentHeading(heading);
      }
    };

    window.addEventListener('deviceorientation', handleOrientation, true);
    window.addEventListener('deviceorientationabsolute', handleOrientation, true);

    return () => {
      if (watchIdRef.current !== null) {
        navigator.geolocation.clearWatch(watchIdRef.current);
      }
      window.removeEventListener('deviceorientation', handleOrientation, true);
      window.removeEventListener('deviceorientationabsolute', handleOrientation, true);
    };
  }, [isCompassActive]);

  const userIcon = useMemo(() => L.divIcon({
    className: '!bg-transparent !border-none',
    html: `<div class="w-8 h-8 bg-blue-600 rounded-full border-2 border-white shadow-xl flex items-center justify-center"><div class="w-2 h-2 bg-white rounded-full"></div></div>`,
    iconSize: [32, 32],
    iconAnchor: [16, 16]
  }), []);

  const destIcon = useMemo(() => L.divIcon({
    className: '!bg-transparent !border-none',
    html: `<div class="w-10 h-10 bg-red-600 rounded-full border-2 border-white shadow-xl flex items-center justify-center text-white text-xs font-black">Đ</div>`,
    iconSize: [40, 40],
    iconAnchor: [20, 20]
  }), []);

  if (!routeData) return null;

  const center: [number, number] = routeData.origin && routeData.destination
    ? [(routeData.origin.lat + routeData.destination.lat) / 2, (routeData.origin.lng + routeData.destination.lng) / 2]
    : [0, 0];

  const centerOnUser = () => {
    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        (position) => {
          if (mapRef.current) {
            const currentZoom = mapRef.current.getZoom();
            mapRef.current.setView([position.coords.latitude, position.coords.longitude], currentZoom, { animate: true });
            canFitRef.current = false;
          }
        },
        (err) => console.error("Cannot get user location:", err),
        { enableHighAccuracy: true }
      );
    }
  };

  return (
    <div className="fixed inset-0 bg-slate-950 flex flex-col overflow-hidden select-none text-white antialiased">
      <div className="w-full bg-[#1e293b]/95 backdrop-blur-md border-b border-slate-800 px-4 py-3.5 flex items-center gap-3 z-50 shrink-0">
        <button
          onClick={onBack}
          className="text-slate-300 hover:text-white p-1 rounded-lg hover:bg-slate-800 transition-colors"
          title="Quay lại danh sách lộ trình"
        >
          <ChevronLeft className="w-6 h-6" />
        </button>
        <h2 className="text-sm font-bold truncate tracking-wide text-slate-100">
          {routeData.tourTitle || "Bản đồ chỉ đường"}
        </h2>
      </div>

      <div className="flex-1 relative min-h-0">
        <MapContainer
          center={center}
          zoom={14}
          className="absolute inset-0 h-full w-full"
          zoomControl={true}
          attributionControl={false}
          scrollWheelZoom={true}
          doubleClickZoom={true}
          touchZoom={true}
          dragging={true}
          inertia={true}
          maxZoom={20}
          minZoom={2}
        >
          <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" attribution="" />
          <MapRefSetter mapRef={mapRef} />
          <MapInteractionWatcher hasInteractedRef={hasInteractedRef} />
          <FitBounds coords={routeGeometry || []} destination={routeData?.destination || null} hasInteractedRef={hasInteractedRef} />
          {routeGeometry && (
            <Polyline positions={routeGeometry} color="#2563eb" weight={6} opacity={0.9} smoothFactor={1} />
          )}
          <MapSizeHandler mapRef={mapRef} />
          <MapRotationHandler rotation={currentHeading} />
          <CompassInteractionDetector onUserInteraction={handleUserInteraction} hasInteractedRef={hasInteractedRef} />
        </MapContainer>

        {/* Locate User Button */}
        <button
          onClick={() => {
            setIsLocatingUser(!isLocatingUser);
            if (!isLocatingUser) {
              centerOnUser();
            }
          }}
          className={`absolute bottom-8 left-6 z-[999] w-14 h-14 rounded-full border-2 flex items-center justify-center shadow-2xl transition-all active:scale-95 ${
            isLocatingUser
              ? 'bg-blue-600 border-blue-400 text-white animate-pulse'
              : 'bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-700 text-slate-600 dark:text-blue-400'
          }`}
          title="Vị trí của tôi"
        >
          <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <circle cx="12" cy="12" r="3" />
            <path d="M12 2v4M12 18v4M2 12h4M18 12h4" />
          </svg>
        </button>

        <button
          onClick={() => setIsCompassActive(!isCompassActive)}
          className={`absolute bottom-8 right-6 z-[999] w-14 h-14 rounded-full border-2 flex items-center justify-center shadow-2xl transition-all active:scale-95 ${
            isCompassActive
              ? 'bg-blue-600 border-blue-400 text-white animate-pulse'
              : 'bg-white dark:bg-slate-900 border-slate-200 dark:border-slate-700 text-slate-600 dark:text-blue-400'
          }`}
        >
          <Compass className="w-7 h-7" />
        </button>

        {error && (
          <div className="absolute top-4 left-1/2 -translate-x-1/2 bg-red-900 text-white text-xs px-3 py-1.5 rounded-lg shadow-lg z-[1000]">
            {error}
          </div>
        )}
      </div>
    </div>
  );
};
