import type { RefObject, ReactElement } from 'react'
import type {
  MapRef,
  ViewState,
  LayerProps,
  FillLayerSpecification,
  CircleLayerSpecification,
  LineLayerSpecification,
  SymbolLayerSpecification,
  ControlPosition,
  MarkerProps,
} from 'react-map-gl/maplibre'
import type { LngLatBoundsLike, LngLat, FilterSpecification } from 'maplibre-gl'

export type { ControlPosition, MarkerProps }

// ============================================================================
// Marker Types
// ============================================================================

export interface MarkerData {
  id: string
  longitude: number
  latitude: number
  data?: Record<string, unknown>
}

// ============================================================================
// Viewport Types
// ============================================================================

export interface MapViewport extends Partial<ViewState> {
  longitude: number
  latitude: number
  zoom: number
  bearing?: number
  pitch?: number
  transitionDuration?: number
}

// ============================================================================
// Context Types
// ============================================================================

export interface MapContextValue {
  mapRef: RefObject<MapRef | null>
  viewport: MapViewport
  setViewport: (viewport: Partial<MapViewport>) => void
  initialViewport: MapViewport
  resetToInitial: () => void
  markers: MarkerData[]
  setMarkers: React.Dispatch<React.SetStateAction<MarkerData[]>>
  selectedMarker: MarkerData | null
  setSelectedMarker: (marker: MarkerData | null) => void
  hoveredFeature: GeoJSON.Feature | null
  setHoveredFeature: (feature: GeoJSON.Feature | null) => void
  isLoaded: boolean
  setIsLoaded: (loaded: boolean) => void
}

// ============================================================================
// Hook Return Types
// ============================================================================

export interface MapControlActions {
  flyTo: (center: [number, number], zoom?: number, options?: { duration?: number }) => void
  easeTo: (center: [number, number], zoom?: number, options?: { duration?: number }) => void
  fitBounds: (bounds: LngLatBoundsLike, options?: { padding?: number; duration?: number }) => void
  zoomIn: () => void
  zoomOut: () => void
  resetView: (initialViewport: MapViewport) => void
  getCenter: () => [number, number] | null
  getZoom: () => number | null
  getBounds: () => LngLatBoundsLike | null
}

export interface MarkerActions {
  markers: MarkerData[]
  addMarker: (marker: Omit<MarkerData, 'id'>) => string
  removeMarker: (id: string) => void
  updateMarker: (id: string, updates: Partial<Omit<MarkerData, 'id'>>) => void
  clearMarkers: () => void
  fitToMarkers: (padding?: number) => void
}

// ============================================================================
// Event Types
// ============================================================================

export interface MapEventHandlers {
  onClick?: (event: MapMouseEvent) => void
  onHover?: (event: MapMouseEvent) => void
  onMoveStart?: () => void
  onMoveEnd?: (viewport: MapViewport) => void
  onZoomStart?: () => void
  onZoomEnd?: (zoom: number) => void
  onLoad?: () => void
}

export interface MapMouseEvent {
  lngLat: LngLat
  point: { x: number; y: number }
  features?: GeoJSON.Feature[]
  originalEvent: MouseEvent
}

// ============================================================================
// Style Types
// ============================================================================

export type MapStyleKey = 'light' | 'dark' | 'streets' | 'satellite'

// ============================================================================
// Layer Types (from react-map-gl & maplibre-gl)
// ============================================================================

export type {
  LayerProps,
  FillLayerSpecification,
  CircleLayerSpecification,
  LineLayerSpecification,
  SymbolLayerSpecification,
  FilterSpecification,
}

export interface ClusterLayerOptions {
  sourceId: string
  colors?: [string, string, string]
  radii?: [number, number, number]
  thresholds?: [number, number]
  hoverColor?: string
}

export interface PointLayerOptions {
  color?: string
  radius?: number
  strokeWidth?: number
  strokeColor?: string
}

export interface PolygonLayerOptions {
  fillColor?: string
  fillOpacity?: number
  strokeColor?: string
  strokeWidth?: number
}

// ============================================================================
// Line Layer Types
// ============================================================================

export interface LineLayerOptions {
  id: string
  sourceId: string
  color?: string
  width?: number
  opacity?: number
  dashArray?: number[]
  lineCap?: 'butt' | 'round' | 'square'
  lineJoin?: 'bevel' | 'round' | 'miter'
  blur?: number
  minZoom?: number
  maxZoom?: number
}

export interface RouteLayerOptions extends Omit<LineLayerOptions, 'id'> {
  sourceId: string
}

// ============================================================================
// Control Types
// ============================================================================

export interface DrawControlProps {
  position?: ControlPosition
  displayControlsDefault?: boolean
  controls?: {
    point?: boolean
    line_string?: boolean
    polygon?: boolean
    trash?: boolean
    combine_features?: boolean
    uncombine_features?: boolean
  }
  defaultMode?: string
  onCreate?: (evt: { features: object[] }) => void
  onUpdate?: (evt: { features: object[]; action: string }) => void
  onDelete?: (evt: { features: object[] }) => void
}

export interface GeocoderControlProps {
  position: ControlPosition
  marker?: boolean | Omit<MarkerProps, 'longitude' | 'latitude'>
  placeholder?: string
  collapsed?: boolean
  clearOnBlur?: boolean
  showResultsWhileTyping?: boolean
  minLength?: number
  limit?: number
  language?: string
  countries?: string
  zoom?: number
  flyTo?: boolean | object
  onLoading?: (e: object) => void
  onResults?: (e: object) => void
  onResult?: (e: object) => void
  onError?: (e: object) => void
}

export interface CustomOverlayProps {
  children: React.ReactNode
}

// ============================================================================
// Legend Types
// ============================================================================

export interface LegendItem {
  id: string
  label: string
  color?: string
  icon?: React.ReactNode
  type?: 'circle' | 'line' | 'fill' | 'symbol'
  visible?: boolean
}

export interface MapLegendProps {
  items: LegendItem[]
  position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
  title?: string
  collapsible?: boolean
  defaultCollapsed?: boolean
  className?: string
  style?: React.CSSProperties
  onItemClick?: (item: LegendItem) => void
}

// ============================================================================
// Layer Switcher Types
// ============================================================================

export interface LayerConfig {
  id: string
  label: string
  defaultVisible?: boolean
  group?: string
}

export interface LayerSwitcherProps {
  layers: LayerConfig[]
  position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
  title?: string
  collapsible?: boolean
  defaultCollapsed?: boolean
  showToggleAll?: boolean
  className?: string
  style?: React.CSSProperties
  onChange?: (layerId: string, visible: boolean) => void
}
