'use client';

import { useEffect, useRef, useState, useMemo } from 'react';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import type { Participant, MapViewport, Waypoint, RouteSegment } from '@/types';
import FriendMarker from './FriendMarker';
import RouteOverlay from './RouteOverlay';

interface MapViewProps {
  participants: Participant[];
  waypoints?: Waypoint[];
  currentUserId?: string;
  initialViewport?: MapViewport;
  onParticipantClick?: (participant: Participant) => void;
  onWaypointClick?: (waypoint: Waypoint) => void;
  onMapClick?: (lngLat: { lng: number; lat: number }) => void;
  /** Auto-center on current user's location when first available */
  autoCenterOnUser?: boolean;
  /** Location to zoom/fly to */
  zoomToLocation?: { latitude: number; longitude: number } | null;
  /** Active route segments to display */
  routeSegments?: RouteSegment[];
  /** Route loading state */
  routeLoading?: boolean;
  /** Route error message */
  routeError?: string;
  /** Route summary text */
  routeSummary?: string;
  /** Total route distance in meters */
  routeDistance?: number;
  /** Estimated route time in seconds */
  routeTime?: number;
  /** Destination name for route */
  routeDestination?: string;
  /** Callback when route is cleared */
  onClearRoute?: () => void;
}

// Default to Hamburg CCH area for CCC events
const DEFAULT_VIEWPORT: MapViewport = {
  center: [9.9898, 53.5550], // Hamburg CCH
  zoom: 15,
};

// Validate coordinates are within valid ranges
function isValidCoordinate(lat: number, lng: number): boolean {
  return (
    typeof lat === 'number' &&
    typeof lng === 'number' &&
    !isNaN(lat) &&
    !isNaN(lng) &&
    lat >= -90 &&
    lat <= 90 &&
    lng >= -180 &&
    lng <= 180
  );
}

// Check if a participant's location is stale (older than 5 minutes)
const STALE_THRESHOLD_MS = 5 * 60 * 1000; // 5 minutes
function isLocationStale(lastSeen: number): boolean {
  return Date.now() - lastSeen > STALE_THRESHOLD_MS;
}

export default function MapView({
  participants,
  waypoints = [],
  currentUserId,
  initialViewport = DEFAULT_VIEWPORT,
  onParticipantClick,
  onWaypointClick,
  onMapClick,
  autoCenterOnUser = true,
  zoomToLocation,
  routeSegments = [],
  routeLoading = false,
  routeError,
  routeSummary,
  routeDistance = 0,
  routeTime = 0,
  routeDestination,
  onClearRoute,
}: MapViewProps) {
  const mapContainer = useRef<HTMLDivElement>(null);
  const map = useRef<maplibregl.Map | null>(null);
  const markersRef = useRef<Map<string, maplibregl.Marker>>(new Map());
  const waypointMarkersRef = useRef<Map<string, maplibregl.Marker>>(new Map());
  const [mapLoaded, setMapLoaded] = useState(false);
  const hasCenteredOnUserRef = useRef(false);

  // Deduplicate participants by name, keeping the most recently seen one
  const dedupedParticipants = useMemo(() => {
    const byName = new Map<string, Participant>();
    for (const p of participants) {
      const existing = byName.get(p.name);
      if (!existing || p.lastSeen > existing.lastSeen) {
        byName.set(p.name, p);
      }
    }
    return Array.from(byName.values());
  }, [participants]);

  // Initialize map
  useEffect(() => {
    if (!mapContainer.current || map.current) return;

    // Validate viewport center coordinates, fall back to default if invalid
    const [lng, lat] = initialViewport.center;
    const validCenter = isValidCoordinate(lat, lng)
      ? initialViewport.center
      : DEFAULT_VIEWPORT.center;

    map.current = new maplibregl.Map({
      container: mapContainer.current,
      style: {
        version: 8,
        sources: {
          osm: {
            type: 'raster',
            // Use Carto's basemaps - more reliable than direct OSM tiles
            tiles: [
              'https://a.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
              'https://b.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
              'https://c.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
              'https://d.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}@2x.png',
            ],
            tileSize: 256,
            attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="https://carto.com/attributions">CARTO</a>',
          },
        },
        layers: [
          {
            id: 'osm',
            type: 'raster',
            source: 'osm',
            minzoom: 0,
            maxzoom: 20,
          },
        ],
      },
      center: validCenter,
      zoom: initialViewport.zoom || DEFAULT_VIEWPORT.zoom,
      bearing: initialViewport.bearing ?? 0,
      pitch: initialViewport.pitch ?? 0,
    });

    // Add controls
    map.current.addControl(new maplibregl.NavigationControl(), 'top-right');
    map.current.addControl(
      new maplibregl.GeolocateControl({
        positionOptions: {
          enableHighAccuracy: true,
        },
        trackUserLocation: true,
        showUserHeading: true,
      } as maplibregl.GeolocateControlOptions),
      'top-right'
    );
    map.current.addControl(new maplibregl.ScaleControl(), 'bottom-left');

    // Handle click events
    map.current.on('click', (e) => {
      onMapClick?.({ lng: e.lngLat.lng, lat: e.lngLat.lat });
    });

    map.current.on('load', () => {
      setMapLoaded(true);
    });

    return () => {
      map.current?.remove();
      map.current = null;
    };
  }, [initialViewport, onMapClick]);

  // Update markers when participants change
  useEffect(() => {
    if (!map.current || !mapLoaded) return;

    console.log('MapView: Updating markers for', dedupedParticipants.length, 'participants');
    dedupedParticipants.forEach((p) => {
      console.log('  -', p.name, p.id, 'location:', p.location ? `${p.location.latitude}, ${p.location.longitude}` : 'none');
    });

    const currentMarkers = markersRef.current;
    const participantIds = new Set(dedupedParticipants.map((p) => p.id));

    // Remove markers for participants who left
    currentMarkers.forEach((marker, id) => {
      if (!participantIds.has(id)) {
        marker.remove();
        currentMarkers.delete(id);
      }
    });

    // Add/update markers for current participants
    dedupedParticipants.forEach((participant) => {
      if (!participant.location) return;

      const { latitude, longitude } = participant.location;

      // Skip invalid coordinates
      if (!isValidCoordinate(latitude, longitude)) {
        console.warn('Invalid coordinates for participant:', participant.id, latitude, longitude);
        return;
      }
      let marker = currentMarkers.get(participant.id);

      if (marker) {
        // Update existing marker position and stale status
        marker.setLngLat([longitude, latitude]);
        const el = marker.getElement();
        const isStale = isLocationStale(participant.lastSeen.getTime());
        if (isStale) {
          el.style.backgroundColor = '#6b7280';
          el.style.opacity = '0.6';
          el.title = `${participant.name} - last seen ${Math.round((Date.now() - participant.lastSeen.getTime()) / 60000)} min ago`;
        } else {
          el.style.backgroundColor = participant.color;
          el.style.opacity = '1';
          el.title = participant.name;
        }
      } else {
        // Create new marker
        const el = document.createElement('div');
        el.className = 'friend-marker';
        el.innerHTML = participant.emoji;

        const isStale = isLocationStale(participant.lastSeen.getTime());

        if (isStale) {
          // Grey out stale locations
          el.style.backgroundColor = '#6b7280'; // gray-500
          el.style.opacity = '0.6';
          el.title = `${participant.name} - last seen ${Math.round((Date.now() - participant.lastSeen.getTime()) / 60000)} min ago`;
        } else {
          el.style.backgroundColor = participant.color;
        }

        if (participant.id === currentUserId) {
          el.classList.add('sharing');
        }

        el.addEventListener('click', (e) => {
          e.stopPropagation();
          onParticipantClick?.(participant);
        });

        marker = new maplibregl.Marker({ element: el })
          .setLngLat([longitude, latitude])
          .addTo(map.current!);

        currentMarkers.set(participant.id, marker);
      }

      // Add accuracy circle if available
      // TODO: Implement accuracy circles as a layer
    });

    // Auto-center on current user's first location
    if (autoCenterOnUser && !hasCenteredOnUserRef.current && currentUserId) {
      const currentUser = dedupedParticipants.find(p => p.id === currentUserId);
      if (currentUser?.location && map.current) {
        const { latitude, longitude } = currentUser.location;
        if (isValidCoordinate(latitude, longitude)) {
          console.log('Auto-centering on user location:', latitude, longitude);
          map.current.flyTo({
            center: [longitude, latitude],
            zoom: 16,
          });
          hasCenteredOnUserRef.current = true;
        }
      }
    }
  }, [dedupedParticipants, mapLoaded, currentUserId, onParticipantClick, autoCenterOnUser]);

  // Fly to location when zoomToLocation changes
  useEffect(() => {
    if (!map.current || !mapLoaded || !zoomToLocation) return;

    const { latitude, longitude } = zoomToLocation;
    if (isValidCoordinate(latitude, longitude)) {
      console.log('Flying to location:', latitude, longitude);
      map.current.flyTo({
        center: [longitude, latitude],
        zoom: 17,
        duration: 1500,
      });
    }
  }, [zoomToLocation, mapLoaded]);

  // Update waypoint markers
  useEffect(() => {
    if (!map.current || !mapLoaded) return;

    const currentWaypointMarkers = waypointMarkersRef.current;
    const waypointIds = new Set(waypoints.map((w) => w.id));

    // Remove markers for deleted waypoints
    currentWaypointMarkers.forEach((marker, id) => {
      if (!waypointIds.has(id)) {
        marker.remove();
        currentWaypointMarkers.delete(id);
      }
    });

    // Add/update waypoint markers
    waypoints.forEach((waypoint) => {
      const { latitude, longitude } = waypoint.location;

      // Skip invalid coordinates
      if (!isValidCoordinate(latitude, longitude)) {
        console.warn('Invalid coordinates for waypoint:', waypoint.id, latitude, longitude);
        return;
      }

      let marker = currentWaypointMarkers.get(waypoint.id);

      if (marker) {
        // Update position if changed
        marker.setLngLat([longitude, latitude]);
      } else {
        // Create new waypoint marker
        const el = document.createElement('div');
        el.className = 'waypoint-marker';
        el.innerHTML = `
          <div class="waypoint-icon">${waypoint.emoji || '📍'}</div>
          <div class="waypoint-label">${waypoint.name}</div>
        `;
        el.style.cssText = `
          display: flex;
          flex-direction: column;
          align-items: center;
          cursor: pointer;
        `;

        const iconDiv = el.querySelector('.waypoint-icon') as HTMLElement;
        if (iconDiv) {
          iconDiv.style.cssText = `
            width: 32px;
            height: 32px;
            background: linear-gradient(135deg, #10b981 0%, #059669 100%);
            border-radius: 50% 50% 50% 0;
            transform: rotate(-45deg);
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 2px 8px rgba(0,0,0,0.3);
          `;
          const innerSpan = document.createElement('span');
          innerSpan.style.cssText = 'transform: rotate(45deg); font-size: 14px;';
          innerSpan.textContent = waypoint.emoji || '📍';
          iconDiv.innerHTML = '';
          iconDiv.appendChild(innerSpan);
        }

        const labelDiv = el.querySelector('.waypoint-label') as HTMLElement;
        if (labelDiv) {
          labelDiv.style.cssText = `
            background: rgba(0,0,0,0.8);
            color: white;
            font-size: 11px;
            padding: 2px 6px;
            border-radius: 4px;
            margin-top: 4px;
            white-space: nowrap;
            max-width: 120px;
            overflow: hidden;
            text-overflow: ellipsis;
          `;
        }

        el.addEventListener('click', (e) => {
          e.stopPropagation();
          onWaypointClick?.(waypoint);
        });

        marker = new maplibregl.Marker({ element: el })
          .setLngLat([longitude, latitude])
          .addTo(map.current!);

        currentWaypointMarkers.set(waypoint.id, marker);
      }
    });
  }, [waypoints, mapLoaded, onWaypointClick]);

  // Fit bounds to show all participants
  const fitToParticipants = () => {
    if (!map.current || dedupedParticipants.length === 0) return;

    const locatedParticipants = dedupedParticipants.filter(
      (p) => p.location && isValidCoordinate(p.location.latitude, p.location.longitude)
    );
    if (locatedParticipants.length === 0) return;

    if (locatedParticipants.length === 1) {
      const loc = locatedParticipants[0].location!;
      map.current.flyTo({
        center: [loc.longitude, loc.latitude],
        zoom: 16,
      });
    } else {
      const bounds = new maplibregl.LngLatBounds();
      locatedParticipants.forEach((p) => {
        bounds.extend([p.location!.longitude, p.location!.latitude]);
      });
      map.current.fitBounds(bounds, { padding: 50 });
    }
  };

  // Check if there are route segments or route is loading/errored
  const hasActiveRoute = routeSegments.length > 0 || routeLoading || routeError;

  return (
    <div className="relative w-full h-full">
      <div ref={mapContainer} className="w-full h-full" />

      {/* Route overlay */}
      {hasActiveRoute && (
        <RouteOverlay
          map={map.current}
          segments={routeSegments}
          isLoading={routeLoading}
          error={routeError}
          summary={routeSummary}
          totalDistance={routeDistance}
          estimatedTime={routeTime}
          destinationName={routeDestination}
          onClose={onClearRoute}
        />
      )}

      {/* Fit all button */}
      {dedupedParticipants.some((p) => p.location) && (
        <button
          onClick={fitToParticipants}
          className="absolute bottom-4 right-4 bg-rmaps-dark/90 text-white px-3 py-2 rounded-lg text-sm hover:bg-rmaps-dark transition-colors"
          title="Show all friends"
        >
          Show All
        </button>
      )}

      {/* Loading overlay */}
      {!mapLoaded && (
        <div className="absolute inset-0 bg-rmaps-dark flex items-center justify-center">
          <div className="text-white/60">Loading map...</div>
        </div>
      )}
    </div>
  );
}
