import {
  createContext,
  useContext,
  useState,
  type PropsWithChildren,
} from 'react'
import { useStore } from 'zustand'
import { createMapStore } from './store'
import type { StoreApi } from 'zustand'
import type { MapProviderProps, MapStore } from './types'

const MapContext = createContext<StoreApi<MapStore>>({} as StoreApi<MapStore>)

/**
 * React context provider that enables declarative map state management through a centralized configuration.
 * Defines multiple map instances with their initial state and makes the map store available to child components.
 *
 * @example
 * ```tsx
 * <MapProvider values={[{ id: 'map1', basemap: CartoBasemaps.positron, viewState: { latitude: 40.7, longitude: -74, zoom: 10 } }]}>
 *   <MapComponent id="map1" />
 * </MapProvider>
 * ```
 */
export function MapProvider({
  children,
  values,
}: PropsWithChildren<MapProviderProps>) {
  const [storeRef] = useState(createMapStore(values))

  return <MapContext.Provider value={storeRef}>{children}</MapContext.Provider>
}

/**
 * Hook to access the centralized map store for managing map instances, layers, view states, and spatial filters.
 * Must be used within a {@link MapProvider} or {@link MapsProvider}.
 *
 * @param selector - Zustand selector function to pick specific state from the store.
 * @returns The selected state value.
 *
 * @remarks
 * Use selective subscriptions to prevent unnecessary re-renders:
 * `useMapStore((state) => state.viewStates[mapId])` instead of selecting the entire state.
 *
 * @example
 * ```tsx
 * const viewState = useMapStore((state) => state.viewStates['main-map'])
 * const setBasemap = useMapStore((state) => state.setBasemap)
 * ```
 */
export function useMapStore<T>(selector: (state: MapStore) => T): T {
  const store = useContext(MapContext)
  if (!Object.keys(store).length)
    throw new Error('Missing MapProvider in the tree')
  return useStore(store, selector)
}
