"use client";

import { useEffect, useState } from "react";
import { MapContainer, TileLayer, Marker, Popup, useMap, Polyline } from "react-leaflet";
import L from "leaflet";
import "leaflet/dist/leaflet.css";
import { toast } from "sonner";
import { useSocket } from "@/hooks/useSocket";

// Type for location
interface LocationType {
  latitude: number;
  longitude: number;
  accuracy?: number;
  timestamp: Date;
}

// Location update handler that recalculates position
function LocationMarker({
  position,
  onLocationUpdate,
  shareToken,
}: {
  position: [number, number] | null;
  onLocationUpdate: (location: LocationType) => void;
  shareToken?: string;
}) {
  const [positionHistory, setPositionHistory] = useState<[number, number][]>([]);
  const [isClient, setIsClient] = useState(false);
  const map = useMap();
  const { sendLocationUpdate, isConnected } = useSocket();

  // Safely check if we're on the client side
  useEffect(() => {
    setIsClient(true);
  }, []);

  useEffect(() => {
    map.locate({ watch: true, enableHighAccuracy: true });

    map.on("locationfound", (e) => {
      const newPosition: [number, number] = [e.latlng.lat, e.latlng.lng];
      
      // Update position history
      setPositionHistory((prev) => [...prev, newPosition]);
      
      // Create location data
      const locationData = {
        latitude: e.latlng.lat,
        longitude: e.latlng.lng,
        accuracy: e.accuracy,
        timestamp: new Date(),
      };
      
      // Notify parent component
      onLocationUpdate(locationData);
      
      // Send location update to Socket.IO if sharing
      if (shareToken && isConnected) {
        sendLocationUpdate({
          latitude: e.latlng.lat,
          longitude: e.latlng.lng,
          accuracy: e.accuracy,
          shareToken,
        });
      }

      // Center map on the new position
      map.flyTo(e.latlng, map.getZoom());
    });

    map.on("locationerror", (e) => {
      toast.error("Error accessing location: " + e.message);
      console.error("Location error: ", e);
    });

    return () => {
      map.stopLocate();
      map.off("locationfound");
      map.off("locationerror");
    };
  }, [map, onLocationUpdate, sendLocationUpdate, shareToken, isConnected]);

  // Return null if position is null or if we're not on client yet
  if (!position || !isClient) return null;
  
  // Only render the polyline if we have enough points and we're on the client side
  const showPolyline = isClient && positionHistory && positionHistory.length > 1;

  return (
    <>
      <Marker position={position}>
        <Popup>
          {shareToken ? "Sharing location in real-time" : "You are here"}
          {isConnected && shareToken && (
            <div className="text-xs mt-1 text-green-600">Connected</div>
          )}
        </Popup>
      </Marker>
      
      {/* Draw path if we have position history and we're on client */}
      {showPolyline && (
        <Polyline
          pathOptions={{ color: "blue", weight: 3 }}
          positions={positionHistory}
        />
      )}
    </>
  );
}

// Component to display a shared location
function SharedLocationMarker({ position, lastUpdate }: { position: [number, number]; lastUpdate?: string }) {
  return (
    <Marker position={position} icon={new L.Icon({
      iconUrl: '/marker-icon-red.png',
      iconRetinaUrl: '/marker-icon-2x-red.png',
      shadowUrl: '/marker-shadow.png',
      iconSize: [25, 41],
      iconAnchor: [12, 41],
      popupAnchor: [1, -34],
      shadowSize: [41, 41]
    })}>
      <Popup>
        <div>
          <div>Shared Location</div>
          {lastUpdate && (
            <div className="text-xs mt-1">Last updated: {new Date(lastUpdate).toLocaleTimeString()}</div>
          )}
        </div>
      </Popup>
    </Marker>
  );
}

export default function Map({
  onLocationUpdate,
  shareToken,
  mode = 'tracking',
  initialLocation,
}: {
  onLocationUpdate?: (location: LocationType) => void;
  shareToken?: string;
  mode?: 'tracking' | 'viewing';
  initialLocation?: { latitude: number; longitude: number };
}) {
  const [position, setPosition] = useState<[number, number] | null>(null);
  const [sharedPosition, setSharedPosition] = useState<[number, number] | null>(null);
  const [lastUpdate, setLastUpdate] = useState<string | undefined>(undefined);
  const [isLoading, setIsLoading] = useState(true);
  const [isClient, setIsClient] = useState(false);
  const { subscribeToLocationUpdates } = useSocket();

  // Check if we're on client side
  useEffect(() => {
    setIsClient(true);
  }, []);

  // Fix Leaflet marker icon issues in Next.js
  useEffect(() => {
    // This is needed to fix the marker icon issues with webpack
    if (typeof window !== "undefined") {
      // @ts-ignore
      delete L.Icon.Default.prototype._getIconUrl;
      L.Icon.Default.mergeOptions({
        iconRetinaUrl: "/marker-icon-2x.png",
        iconUrl: "/marker-icon.png",
        shadowUrl: "/marker-shadow.png",
      });
    }
  }, []);

  // Subscribe to real-time location updates when viewing shared location
  useEffect(() => {
    if (mode === 'viewing' && shareToken && isClient) {
      // If we have initial location, set it
      if (initialLocation) {
        setSharedPosition([initialLocation.latitude, initialLocation.longitude]);
        setIsLoading(false);
      }
      
      // Subscribe to real-time updates
      const cleanup = subscribeToLocationUpdates(shareToken, (data) => {
        console.log('Received location update:', data);
        setSharedPosition([data.latitude, data.longitude]);
        setLastUpdate(data.timestamp);
        toast.info('Location updated');
      });
      
      return cleanup;
    }
  }, [mode, shareToken, subscribeToLocationUpdates, initialLocation, isClient]);

  useEffect(() => {
    if (!isClient) return;
    
    // Only get current position in tracking mode
    if (mode === 'tracking') {
      // Try to get initial position
      navigator.geolocation.getCurrentPosition(
        (position) => {
          setPosition([position.coords.latitude, position.coords.longitude]);
          setIsLoading(false);
          
          if (onLocationUpdate) {
            onLocationUpdate({
              latitude: position.coords.latitude,
              longitude: position.coords.longitude,
              accuracy: position.coords.accuracy,
              timestamp: new Date(position.timestamp),
            });
          }
        },
        (error) => {
          toast.error(`Error getting location: ${error.message}`);
          setIsLoading(false);
        },
        { enableHighAccuracy: true }
      );
    }
  }, [onLocationUpdate, isClient, mode]);

  // Handle location updates from the marker component
  const handleLocationUpdate = (location: LocationType) => {
    setPosition([location.latitude, location.longitude]);
    if (onLocationUpdate) {
      onLocationUpdate(location);
    }
  };

  if (!isClient || isLoading) {
    return <div className="h-full w-full flex items-center justify-center">Loading map...</div>;
  }

  // Determine which position to center on
  let defaultPosition: [number, number];
  if (mode === 'viewing' && sharedPosition) {
    defaultPosition = sharedPosition;
  } else if (position) {
    defaultPosition = position;
  } else {
    defaultPosition = [51.505, -0.09]; // Default to London
  }

  return (
    <div className="h-full w-full">
      <MapContainer
        center={defaultPosition}
        zoom={13}
        style={{ height: "100%", width: "100%" }}
      >
        <TileLayer
          attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
        />
        
        {/* Show our location marker in tracking mode */}
        {mode === 'tracking' && position && (
          <LocationMarker 
            position={position} 
            onLocationUpdate={handleLocationUpdate} 
            shareToken={shareToken}
          />
        )}
        
        {/* Show shared location marker in viewing mode */}
        {mode === 'viewing' && sharedPosition && (
          <SharedLocationMarker position={sharedPosition} lastUpdate={lastUpdate} />
        )}
      </MapContainer>
    </div>
  );
} 