import { useEffect, useMemo, useRef } from 'react'
import { useQuery } from '@tanstack/react-query'
import { MapContainer, TileLayer, useMap } from 'react-leaflet'
import L from 'leaflet'
import { photos as photosApi } from '../../services/api'
import { usePhotoStore } from '../../store/photoStore'
import { MapPin } from 'lucide-react'

interface MapPoint {
  id: string
  latitude: number
  longitude: number
  taken_at: string | null
}

/** Adds all points as native Leaflet circleMarkers on a single canvas
 *  layer — no React components per marker, no clustering library.
 *  3K+ markers render in <50ms on canvas. */
function CanvasMarkers({
  points,
  onClickId,
}: {
  points: MapPoint[]
  onClickId: (id: string) => void
}) {
  const map = useMap()
  const layerRef = useRef<L.LayerGroup | null>(null)
  const fittedRef = useRef(false)

  useEffect(() => {
    if (!map || points.length === 0) return

    // Remove previous layer if data changed.
    if (layerRef.current) {
      map.removeLayer(layerRef.current)
    }

    const group = L.layerGroup()
    const renderer = L.canvas({ padding: 0.5 })

    for (const p of points) {
      const marker = L.circleMarker([p.latitude, p.longitude], {
        renderer,
        radius: 5,
        fillColor: '#3b82f6',
        fillOpacity: 0.85,
        color: '#ffffff',
        weight: 1.5,
        opacity: 0.9,
      })
      marker.on('click', () => onClickId(p.id))
      group.addLayer(marker)
    }

    group.addTo(map)
    layerRef.current = group

    // Fit bounds once on first data load.
    if (!fittedRef.current) {
      const bounds = L.latLngBounds(
        points.map((p) => [p.latitude, p.longitude] as [number, number])
      )
      map.fitBounds(bounds, { padding: [40, 40], maxZoom: 14 })
      fittedRef.current = true
    }

    return () => {
      if (layerRef.current) {
        map.removeLayer(layerRef.current)
        layerRef.current = null
      }
    }
  }, [map, points, onClickId])

  return null
}

export function MapView() {
  const { data: points = [], isLoading, error } = useQuery({
    queryKey: ['photos', 'map'],
    queryFn: () => photosApi.mapPoints(),
    staleTime: 5 * 60 * 1000,
  })

  const openPreview = usePhotoStore((s) => s.openPreview)
  const visibleSequence = useMemo(() => points.map((p) => p.id), [points])

  const handleClick = useMemo(
    () => (id: string) => openPreview(id, visibleSequence),
    [openPreview, visibleSequence],
  )

  if (isLoading) {
    return (
      <div className="flex h-full items-center justify-center text-sm text-muted-foreground">
        Loading map…
      </div>
    )
  }

  if (error) {
    return (
      <div className="flex h-full items-center justify-center text-sm text-destructive">
        Failed to load map photos
      </div>
    )
  }

  return (
    <div className="relative h-full w-full">
      {points.length === 0 ? (
        <div className="absolute inset-0 z-[400] flex items-center justify-center bg-background/80 pointer-events-none">
          <div className="flex flex-col items-center gap-2 text-center text-sm text-muted-foreground">
            <MapPin className="h-6 w-6" />
            <div>No photos with GPS data yet.</div>
            <div className="text-xs">
              Re-run metadata extraction from Settings → Backfill GPS to
              populate coordinates from existing photos.
            </div>
          </div>
        </div>
      ) : null}

      <MapContainer
        center={[20, 0]}
        zoom={2}
        minZoom={2}
        worldCopyJump
        preferCanvas
        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"
        />
        <CanvasMarkers points={points} onClickId={handleClick} />
      </MapContainer>
    </div>
  )
}
