'use client'

import { useCallback, useEffect } from 'react';

import { useMapContext } from '../context';

import type { MapEventHandlers, MapMouseEvent, MapViewport } from '../types'

/**
 * Hook for subscribing to map events
 * Automatically cleans up event listeners on unmount
 */
export function useMapEvents(handlers: MapEventHandlers) {
  const { mapRef, setViewport, setHoveredFeature, isLoaded } = useMapContext()

  const handleClick = useCallback(
    (event: maplibregl.MapMouseEvent & { features?: GeoJSON.Feature[] }) => {
      if (!handlers.onClick) return

      const mapEvent: MapMouseEvent = {
        lngLat: event.lngLat,
        point: event.point,
        features: event.features,
        originalEvent: event.originalEvent,
      }
      handlers.onClick(mapEvent)
    },
    [handlers]
  )

  const handleMouseMove = useCallback(
    (event: maplibregl.MapMouseEvent & { features?: GeoJSON.Feature[] }) => {
      if (!handlers.onHover) return

      const feature = event.features?.[0] ?? null
      setHoveredFeature(feature)

      const mapEvent: MapMouseEvent = {
        lngLat: event.lngLat,
        point: event.point,
        features: event.features,
        originalEvent: event.originalEvent,
      }
      handlers.onHover(mapEvent)
    },
    [handlers, setHoveredFeature]
  )

  const handleMoveStart = useCallback(() => {
    handlers.onMoveStart?.()
  }, [handlers])

  const handleMoveEnd = useCallback(() => {
    const map = mapRef.current
    if (!map) return

    const center = map.getCenter()
    const zoom = map.getZoom()
    const bearing = map.getBearing()
    const pitch = map.getPitch()

    const newViewport: MapViewport = {
      longitude: center.lng,
      latitude: center.lat,
      zoom,
      bearing,
      pitch,
    }

    setViewport(newViewport)
    handlers.onMoveEnd?.(newViewport)
  }, [mapRef, setViewport, handlers])

  const handleZoomStart = useCallback(() => {
    handlers.onZoomStart?.()
  }, [handlers])

  const handleZoomEnd = useCallback(() => {
    const zoom = mapRef.current?.getZoom()
    if (zoom !== undefined) {
      handlers.onZoomEnd?.(zoom)
    }
  }, [mapRef, handlers])

  const handleLoad = useCallback(() => {
    handlers.onLoad?.()
  }, [handlers])

  useEffect(() => {
    const map = mapRef.current?.getMap()
    if (!map || !isLoaded) return

    if (handlers.onClick) {
      map.on('click', handleClick)
    }
    if (handlers.onHover) {
      map.on('mousemove', handleMouseMove)
    }
    if (handlers.onMoveStart) {
      map.on('movestart', handleMoveStart)
    }
    if (handlers.onMoveEnd) {
      map.on('moveend', handleMoveEnd)
    }
    if (handlers.onZoomStart) {
      map.on('zoomstart', handleZoomStart)
    }
    if (handlers.onZoomEnd) {
      map.on('zoomend', handleZoomEnd)
    }

    return () => {
      if (handlers.onClick) {
        map.off('click', handleClick)
      }
      if (handlers.onHover) {
        map.off('mousemove', handleMouseMove)
      }
      if (handlers.onMoveStart) {
        map.off('movestart', handleMoveStart)
      }
      if (handlers.onMoveEnd) {
        map.off('moveend', handleMoveEnd)
      }
      if (handlers.onZoomStart) {
        map.off('zoomstart', handleZoomStart)
      }
      if (handlers.onZoomEnd) {
        map.off('zoomend', handleZoomEnd)
      }
    }
  }, [
    mapRef,
    isLoaded,
    handlers,
    handleClick,
    handleMouseMove,
    handleMoveStart,
    handleMoveEnd,
    handleZoomStart,
    handleZoomEnd,
  ])

  useEffect(() => {
    if (isLoaded && handlers.onLoad) {
      handleLoad()
    }
  }, [isLoaded, handlers.onLoad, handleLoad])
}
