import { PathLayer, ScatterplotLayer, TextLayer } from '@deck.gl/layers';
import type { Layer, PickingInfo } from '@deck.gl/core';
import { DEPTH_DISABLED_PARAMS } from '../../../shared/lib/map/mapConstants';
import { getShipKindColor } from '../lib/adapters';
import type { CurrentVesselPosition, ProcessedTrack } from '../model/track.types';

export const TRACK_REPLAY_LAYER_IDS = {
  PATH: 'track-replay-path',
  POINTS: 'track-replay-points',
  VIRTUAL_SHIP: 'track-replay-virtual-ship',
  VIRTUAL_LABEL: 'track-replay-virtual-label',
  TRAIL: 'track-replay-trail',
} as const;

interface PathData {
  vesselId: string;
  path: [number, number][];
  color: [number, number, number, number];
}

interface PointData {
  vesselId: string;
  position: [number, number];
  color: [number, number, number, number];
  timestamp: number;
  speed: number;
  index: number;
}

const MAX_POINTS_PER_TRACK = 800;

export function createStaticTrackLayers(options: {
  tracks: ProcessedTrack[];
  showPoints: boolean;
  highlightedVesselId?: string | null;
  onPathHover?: (vesselId: string | null) => void;
}): Layer[] {
  const { tracks, showPoints, highlightedVesselId, onPathHover } = options;
  const layers: Layer[] = [];
  if (!tracks || tracks.length === 0) return layers;

  const pathData: PathData[] = tracks.map((track) => ({
    vesselId: track.vesselId,
    path: track.geometry,
    color: getShipKindColor(track.shipKindCode),
  }));

  layers.push(
    new PathLayer<PathData>({
      id: TRACK_REPLAY_LAYER_IDS.PATH,
      data: pathData,
      getPath: (d) => d.path,
      getColor: (d) =>
        highlightedVesselId && highlightedVesselId === d.vesselId
          ? [255, 255, 0, 255]
          : [d.color[0], d.color[1], d.color[2], 235],
      getWidth: (d) => (highlightedVesselId && highlightedVesselId === d.vesselId ? 5 : 3),
      widthUnits: 'pixels',
      widthMinPixels: 1,
      widthMaxPixels: 6,
      parameters: DEPTH_DISABLED_PARAMS,
      jointRounded: true,
      capRounded: true,
      pickable: true,
      onHover: (info: PickingInfo<PathData>) => {
        onPathHover?.(info.object?.vesselId ?? null);
      },
      updateTriggers: {
        getColor: [highlightedVesselId],
        getWidth: [highlightedVesselId],
      },
    }),
  );

  if (showPoints) {
    const pointData: PointData[] = [];

    for (const track of tracks) {
      const color = getShipKindColor(track.shipKindCode);
      const len = track.geometry.length;
      if (len <= MAX_POINTS_PER_TRACK) {
        for (let i = 0; i < len; i++) {
          pointData.push({
            vesselId: track.vesselId,
            position: track.geometry[i],
            color,
            timestamp: track.timestampsMs[i] || 0,
            speed: track.speeds[i] || 0,
            index: i,
          });
        }
      } else {
        const step = len / MAX_POINTS_PER_TRACK;
        for (let i = 0; i < MAX_POINTS_PER_TRACK; i++) {
          const idx = Math.min(Math.floor(i * step), len - 1);
          pointData.push({
            vesselId: track.vesselId,
            position: track.geometry[idx],
            color,
            timestamp: track.timestampsMs[idx] || 0,
            speed: track.speeds[idx] || 0,
            index: idx,
          });
        }
      }
    }

    layers.push(
      new ScatterplotLayer<PointData>({
        id: TRACK_REPLAY_LAYER_IDS.POINTS,
        data: pointData,
        getPosition: (d) => d.position,
        getFillColor: (d) => d.color,
        getRadius: 3,
        radiusUnits: 'pixels',
        radiusMinPixels: 2,
        radiusMaxPixels: 5,
        parameters: DEPTH_DISABLED_PARAMS,
        pickable: false,
      }),
    );
  }

  return layers;
}

export function createDynamicTrackLayers(options: {
  currentPositions: CurrentVesselPosition[];
  showVirtualShip: boolean;
  showLabels: boolean;
  onIconHover?: (position: CurrentVesselPosition | null, x: number, y: number) => void;
  onPathHover?: (vesselId: string | null) => void;
}): Layer[] {
  const { currentPositions, showVirtualShip, showLabels, onIconHover, onPathHover } = options;
  const layers: Layer[] = [];

  if (!currentPositions || currentPositions.length === 0) return layers;

  if (showVirtualShip) {
    layers.push(
      new ScatterplotLayer<CurrentVesselPosition>({
        id: TRACK_REPLAY_LAYER_IDS.VIRTUAL_SHIP,
        data: currentPositions,
        getPosition: (d) => d.position,
        getFillColor: (d) => {
          const base = getShipKindColor(d.shipKindCode);
          return [base[0], base[1], base[2], 230] as [number, number, number, number];
        },
        getLineColor: [255, 255, 255, 200],
        getRadius: 5,
        radiusUnits: 'pixels',
        radiusMinPixels: 4,
        radiusMaxPixels: 8,
        stroked: true,
        lineWidthMinPixels: 1,
        parameters: DEPTH_DISABLED_PARAMS,
        pickable: true,
        onHover: (info: PickingInfo<CurrentVesselPosition>) => {
          if (info.object) {
            onPathHover?.(info.object.vesselId);
            onIconHover?.(info.object, info.x, info.y);
          } else {
            onPathHover?.(null);
            onIconHover?.(null, 0, 0);
          }
        },
      }),
    );
  }

  if (showLabels) {
    const labelData = currentPositions.filter((position) => (position.shipName || '').trim().length > 0);
    if (labelData.length > 0) {
      layers.push(
        new TextLayer<CurrentVesselPosition>({
          id: TRACK_REPLAY_LAYER_IDS.VIRTUAL_LABEL,
          data: labelData,
          getPosition: (d) => d.position,
          getText: (d) => d.shipName,
          getColor: [226, 232, 240, 240],
          getSize: 11,
          getTextAnchor: 'start',
          getAlignmentBaseline: 'center',
          getPixelOffset: [14, 0],
          fontFamily: 'Malgun Gothic, Arial, sans-serif',
          fontSettings: { sdf: true },
          outlineColor: [2, 6, 23, 220],
          outlineWidth: 2,
          parameters: DEPTH_DISABLED_PARAMS,
          pickable: false,
        }),
      );
    }
  }

  return layers;
}

export function isTrackReplayLayerId(id: unknown): boolean {
  return typeof id === 'string' && id.startsWith('track-replay-');
}
