import { useEffect } from 'react';
import { useControl } from 'react-map-gl/maplibre';
import { MapboxOverlay } from '@deck.gl/mapbox';

interface DeckWithPrivateDraw {
  _drawLayers?: (
    redrawReason: string,
    renderOptions?: { viewports?: unknown[]; [key: string]: unknown }
  ) => unknown;
  __propertyMapNullViewportPatch?: boolean;
}

function patchNullViewportDraw(overlay: MapboxOverlay) {
  const deck = (overlay as unknown as { _deck?: DeckWithPrivateDraw })._deck;
  if (!deck || deck.__propertyMapNullViewportPatch || typeof deck._drawLayers !== 'function') {
    return;
  }

  const drawLayers = deck._drawLayers.bind(deck);
  deck._drawLayers = (redrawReason, renderOptions) => {
    const viewports = renderOptions?.viewports;
    if (viewports) {
      // Split-route startup can hand deck.gl a transient null viewport before MapLibre has sized the map.
      const nonNullViewports = viewports.filter(Boolean);
      if (nonNullViewports.length === 0) return;
      if (nonNullViewports.length !== viewports.length) {
        return drawLayers(redrawReason, { ...renderOptions, viewports: nonNullViewports });
      }
    }
    return drawLayers(redrawReason, renderOptions);
  };
  deck.__propertyMapNullViewportPatch = true;
}

class SafeMapboxOverlay extends MapboxOverlay {
  onAdd(map: unknown) {
    const element = super.onAdd(map);
    patchNullViewportDraw(this);
    return element;
  }

  setProps(props: Parameters<MapboxOverlay['setProps']>[0]) {
    super.setProps(props);
    patchNullViewportDraw(this);
  }
}

export function DeckOverlay({
  layers,
  getTooltip,
}: {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  layers: any[];
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  getTooltip: any;
}) {
  const overlay = useControl(() => new SafeMapboxOverlay({ interleaved: true }));

  useEffect(() => {
    overlay.setProps({
      layers: layers.filter(Boolean),
      getTooltip,
    });
  }, [overlay, layers, getTooltip]);

  return null;
}
