import {
  AttributionControl,
  Map,
  MapProvider,
  useMap as useMapLibre,
} from 'react-map-gl/maplibre'
import type { DeckGLComponentProps, InstanceRef } from '../types'
import DeckGL from '@deck.gl/react'
import { useImperativeHandle, type RefObject } from 'react'
import { useInstantiatedLayers } from './use-instantiated-layers'

export function MapLibre({
  instanceRef,
  overlayRef,
  controller,
  id,
  layers,
  mapStyle,
  parameters,
  getCursor,
  getTooltip,
  onLoad,
  onIdle,
  onViewStateChange,
  attributionProps,
  ...rest
}: Omit<DeckGLComponentProps, 'onLoad'> & {
  onLoad: (event: { type: 'deckgl' | 'load'; value: boolean }) => void
  mapStyle: string | undefined
}) {
  const _layers = useInstantiatedLayers(layers)

  return (
    <MapProvider>
      <div className='deckgl-map'>
        <DeckGL
          controller={controller}
          id={id}
          ref={instanceRef as RefObject<InstanceRef>}
          layers={_layers}
          getCursor={getCursor}
          getTooltip={getTooltip}
          onLoad={() =>
            onLoad({
              type: 'deckgl',
              value: true,
            })
          }
          onViewStateChange={onViewStateChange}
          parameters={{
            // @ts-expect-error - `depthTest` is not in the types
            depthTest: false,
            ...parameters,
          }}
          {...rest}
        >
          <MapReferences overlayRef={overlayRef} />
          <Map
            reuseMaps={false}
            mapStyle={mapStyle}
            attributionControl={false}
            onLoad={() =>
              onLoad({
                type: 'load',
                value: true,
              })
            }
            onIdle={onIdle}
          >
            <AttributionControl compact={false} {...attributionProps} />
          </Map>
        </DeckGL>
      </div>
    </MapProvider>
  )
}

function MapReferences({
  overlayRef,
}: {
  overlayRef: DeckGLComponentProps['overlayRef']
}) {
  const { default: mapLibre } = useMapLibre()

  useImperativeHandle(overlayRef, () => {
    return mapLibre
  }, [mapLibre])

  return null
}
