import { useEffect, useMemo, type MutableRefObject } from 'react';
import type maplibregl from 'maplibre-gl';
import type { ActiveTrack } from '../../../entities/vesselTrack/model/types';
import { convertLegacyTrackPointsToProcessedTrack } from '../../../features/trackReplay/lib/adapters';
import { useTrackQueryStore } from '../../../features/trackReplay/stores/trackQueryStore';
import type { TrackReplayDeckRenderState } from '../../../features/trackReplay/hooks/useTrackReplayDeckLayers';
import { useNativeMapLayers, type NativeLayerSpec, type NativeSourceConfig } from './useNativeMapLayers';
import type { MapProjectionId } from '../types';
import { kickRepaint } from '../lib/mapCore';

const GLOBE_LINE_SRC = 'track-replay-globe-line-src';
const GLOBE_POINT_SRC = 'track-replay-globe-point-src';
const GLOBE_VIRTUAL_SRC = 'track-replay-globe-virtual-src';
const GLOBE_TRACK_LAYER_IDS = {
  PATH: 'track-replay-globe-path',
  POINTS: 'track-replay-globe-points',
  VIRTUAL_SHIP: 'track-replay-globe-virtual-ship',
  VIRTUAL_LABEL: 'track-replay-globe-virtual-label',
} as const;

function toFiniteNumber(value: unknown): number | null {
  if (typeof value === 'number') return Number.isFinite(value) ? value : null;
  if (typeof value === 'string') {
    const parsed = Number(value.trim());
    return Number.isFinite(parsed) ? parsed : null;
  }
  return null;
}

function normalizeCoordinate(value: unknown): [number, number] | null {
  if (!Array.isArray(value) || value.length !== 2) return null;
  const lon = toFiniteNumber(value[0]);
  const lat = toFiniteNumber(value[1]);
  if (lon == null || lat == null) return null;
  return [lon, lat];
}

export function useTrackReplayLayer(
  mapRef: MutableRefObject<maplibregl.Map | null>,
  projectionBusyRef: MutableRefObject<boolean>,
  reorderGlobeFeatureLayers: () => void,
  opts: {
    projection: MapProjectionId;
    mapSyncEpoch: number;
    activeTrack?: ActiveTrack | null;
    renderState: TrackReplayDeckRenderState;
  },
) {
  const { projection, mapSyncEpoch, activeTrack = null, renderState } = opts;
  const { enabledTracks, currentPositions, showPoints, showVirtualShip, showLabels, renderEpoch } = renderState;

  const setTracks = useTrackQueryStore((state) => state.setTracks);

  // Backward compatibility path: if legacy activeTrack is provided, load it into the new store.
  useEffect(() => {
    if (!activeTrack) return;
    if (!activeTrack.points || activeTrack.points.length === 0) return;

    const converted = convertLegacyTrackPointsToProcessedTrack(activeTrack.mmsi, activeTrack.points);
    if (!converted) return;

    setTracks([converted]);
  }, [activeTrack, setTracks]);

  const lineGeoJson = useMemo<GeoJSON.FeatureCollection<GeoJSON.LineString>>(() => {
    const features: GeoJSON.Feature<GeoJSON.LineString>[] = [];
    for (const track of enabledTracks) {
      const coordinates: [number, number][] = [];
      for (const coord of track.geometry) {
        const normalized = normalizeCoordinate(coord);
        if (normalized) coordinates.push(normalized);
      }
      if (coordinates.length < 2) continue;

      features.push({
        type: 'Feature',
        properties: {
          vesselId: track.vesselId,
          shipName: track.shipName,
        },
        geometry: {
          type: 'LineString',
          coordinates,
        },
      });
    }

    return {
      type: 'FeatureCollection',
      features,
    };
  }, [enabledTracks]);

  const pointGeoJson = useMemo<GeoJSON.FeatureCollection<GeoJSON.Point>>(() => {
    const features: GeoJSON.Feature<GeoJSON.Point>[] = [];
    for (const track of enabledTracks) {
      track.geometry.forEach((coord, index) => {
        const normalized = normalizeCoordinate(coord);
        if (!normalized) return;
        features.push({
          type: 'Feature',
          properties: {
            vesselId: track.vesselId,
            shipName: track.shipName,
            index,
          },
          geometry: {
            type: 'Point',
            coordinates: normalized,
          },
        });
      });
    }

    return {
      type: 'FeatureCollection',
      features,
    };
  }, [enabledTracks]);

  const virtualGeoJson = useMemo<GeoJSON.FeatureCollection<GeoJSON.Point>>(() => {
    const features: GeoJSON.Feature<GeoJSON.Point>[] = [];
    for (const position of currentPositions) {
      const normalized = normalizeCoordinate(position.position);
      if (!normalized) continue;
      features.push({
        type: 'Feature',
        properties: {
          vesselId: position.vesselId,
          shipName: position.shipName,
        },
        geometry: {
          type: 'Point',
          coordinates: normalized,
        },
      });
    }

    return {
      type: 'FeatureCollection',
      features,
    };
  }, [currentPositions]);

  const globeSources = useMemo<NativeSourceConfig[]>(
    () => [
      { id: GLOBE_LINE_SRC, data: lineGeoJson },
      { id: GLOBE_POINT_SRC, data: pointGeoJson },
      { id: GLOBE_VIRTUAL_SRC, data: virtualGeoJson },
    ],
    [lineGeoJson, pointGeoJson, virtualGeoJson],
  );

  const globeLayers = useMemo<NativeLayerSpec[]>(
    () => [
      {
        id: GLOBE_TRACK_LAYER_IDS.PATH,
        type: 'line',
        sourceId: GLOBE_LINE_SRC,
        paint: {
          'line-color': '#00d1ff',
          'line-width': ['interpolate', ['linear'], ['zoom'], 3, 1.5, 8, 3, 12, 4],
          'line-opacity': 0.8,
        },
        layout: {
          'line-cap': 'round',
          'line-join': 'round',
        },
      },
      {
        id: GLOBE_TRACK_LAYER_IDS.POINTS,
        type: 'circle',
        sourceId: GLOBE_POINT_SRC,
        paint: {
          'circle-radius': ['interpolate', ['linear'], ['zoom'], 3, 1.5, 8, 3, 12, 4],
          'circle-color': '#00d1ff',
          'circle-opacity': showPoints ? 0.8 : 0,
          'circle-stroke-width': 1,
          'circle-stroke-color': 'rgba(2,6,23,0.8)',
        },
      },
      {
        id: GLOBE_TRACK_LAYER_IDS.VIRTUAL_SHIP,
        type: 'circle',
        sourceId: GLOBE_VIRTUAL_SRC,
        paint: {
          'circle-radius': ['interpolate', ['linear'], ['zoom'], 3, 2.5, 8, 4, 12, 6],
          'circle-color': '#f59e0b',
          'circle-opacity': showVirtualShip ? 0.9 : 0,
          'circle-stroke-width': 1,
          'circle-stroke-color': 'rgba(255,255,255,0.8)',
        },
      },
      {
        id: GLOBE_TRACK_LAYER_IDS.VIRTUAL_LABEL,
        type: 'symbol',
        sourceId: GLOBE_VIRTUAL_SRC,
        paint: {
          'text-color': 'rgba(226,232,240,0.95)',
          'text-opacity': showLabels ? 1 : 0,
          'text-halo-color': 'rgba(2,6,23,0.85)',
          'text-halo-width': 1,
        },
        layout: {
          'text-field': ['get', 'shipName'],
          'text-size': 11,
          'text-anchor': 'left',
          'text-offset': [0.8, 0],
        },
      },
    ],
    [showLabels, showPoints, showVirtualShip],
  );

  const isGlobeVisible = projection === 'globe' && enabledTracks.length > 0;

  useNativeMapLayers(
    mapRef,
    projectionBusyRef,
    reorderGlobeFeatureLayers,
    {
      sources: globeSources,
      layers: globeLayers,
      visible: isGlobeVisible,
      beforeLayer: ['zones-fill', 'zones-line'],
    },
    [projection, mapSyncEpoch, renderEpoch, lineGeoJson, pointGeoJson, virtualGeoJson, showPoints, showVirtualShip, showLabels],
  );

  useEffect(() => {
    if (projection !== 'globe') return;
    if (!isGlobeVisible) return;
    const map = mapRef.current;
    if (!map || projectionBusyRef.current) return;

    kickRepaint(map);
    const id = requestAnimationFrame(() => {
      kickRepaint(map);
    });
    return () => cancelAnimationFrame(id);
  }, [projection, isGlobeVisible, renderEpoch, mapRef, projectionBusyRef]);
}
