import { useEffect, useMemo, useRef, useState, type MutableRefObject } from 'react';
import type maplibregl from 'maplibre-gl';
import type { AisTarget } from '../../../entities/aisTarget/model/types';
import ShipBatchRenderer from '../core/ShipBatchRenderer';
import type { LiveShipFeature, ViewportBounds } from '../model/liveShip.types';

interface UseLiveShipBatchRenderResult {
  renderedFeatures: LiveShipFeature[];
  renderedTargets: AisTarget[];
  renderedMmsiSet: Set<number>;
}

function getMapBounds(map: maplibregl.Map): ViewportBounds {
  const bounds = map.getBounds();
  return {
    minLon: bounds.getWest(),
    maxLon: bounds.getEast(),
    minLat: bounds.getSouth(),
    maxLat: bounds.getNorth(),
  };
}

export function useLiveShipBatchRender(
  mapRef: MutableRefObject<maplibregl.Map | null>,
  features: LiveShipFeature[],
  sourceTargets: AisTarget[],
  mapSyncEpoch: number,
): UseLiveShipBatchRenderResult {
  const rendererRef = useRef<ShipBatchRenderer | null>(null);
  const [renderedFeatures, setRenderedFeatures] = useState<LiveShipFeature[]>([]);

  useEffect(() => {
    const renderer = new ShipBatchRenderer();
    renderer.initialize((ships) => {
      setRenderedFeatures(ships);
    });
    rendererRef.current = renderer;

    return () => {
      renderer.dispose();
      rendererRef.current = null;
    };
  }, []);

  useEffect(() => {
    const renderer = rendererRef.current;
    if (!renderer) return;
    renderer.setData(features);
    renderer.immediateRender();
  }, [features]);

  useEffect(() => {
    const map = mapRef.current;
    const renderer = rendererRef.current;
    if (!map || !renderer) return;

    const sync = () => {
      if (!rendererRef.current) return;
      renderer.setZoom(map.getZoom());
      renderer.setViewportBounds(getMapBounds(map));
      renderer.requestRender();
    };

    sync();
    map.on('moveend', sync);
    map.on('zoomend', sync);

    return () => {
      map.off('moveend', sync);
      map.off('zoomend', sync);
    };
  }, [mapRef, mapSyncEpoch]);

  const renderedMmsiSet = useMemo(() => {
    const next = new Set<number>();
    for (const feature of renderedFeatures) {
      next.add(feature.mmsi);
    }
    return next;
  }, [renderedFeatures]);

  const renderedTargets = useMemo(() => {
    if (renderedMmsiSet.size === 0) return [];
    return sourceTargets.filter((target) => renderedMmsiSet.has(target.mmsi));
  }, [sourceTargets, renderedMmsiSet]);

  return { renderedFeatures, renderedTargets, renderedMmsiSet };
}
