import type { TrackPoint } from '../../../entities/vesselTrack/model/types';
import type { ProcessedTrack, TrackStats } from '../model/track.types';

const DEFAULT_SHIP_KIND = '000027';
const DEFAULT_SIGNAL_SOURCE = '000001';
const EPSILON_DISTANCE = 1e-10;

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;
}

export function normalizeTrackTimestampMs(value: string | number | undefined | null): number {
  if (typeof value === 'number') {
    return value < 1e12 ? value * 1000 : value;
  }

  if (typeof value === 'string' && value.trim().length > 0) {
    if (/^\d{10,}$/.test(value)) {
      const asNum = Number(value);
      return asNum < 1e12 ? asNum * 1000 : asNum;
    }

    const parsed = new Date(value).getTime();
    if (Number.isFinite(parsed)) return parsed;
  }

  return Date.now();
}

function calculateStats(points: TrackPoint[]): TrackStats {
  let maxSpeed = 0;
  let speedSum = 0;

  for (const point of points) {
    const speed = Number.isFinite(point.sog) ? point.sog : 0;
    maxSpeed = Math.max(maxSpeed, speed);
    speedSum += speed;
  }

  return {
    totalDistanceNm: 0,
    avgSpeed: points.length > 0 ? speedSum / points.length : 0,
    maxSpeed,
    pointCount: points.length,
  };
}

export function convertLegacyTrackPointsToProcessedTrack(
  mmsi: number,
  points: TrackPoint[],
  hints?: {
    shipName?: string;
    shipKindCode?: string;
    nationalCode?: string;
    sigSrcCd?: string;
  },
): ProcessedTrack | null {
  const sorted = [...points].sort(
    (a, b) => normalizeTrackTimestampMs(a.messageTimestamp) - normalizeTrackTimestampMs(b.messageTimestamp),
  );

  if (sorted.length === 0) return null;

  const first = sorted[0];
  const normalizedPoints = sorted
    .map((point) => {
      const lon = toFiniteNumber(point.lon);
      const lat = toFiniteNumber(point.lat);
      if (lon == null || lat == null) return null;

      const ts = normalizeTrackTimestampMs(point.messageTimestamp);
      const speed = toFiniteNumber(point.sog) ?? 0;
      return {
        point,
        lon,
        lat,
        ts,
        speed,
      };
    })
    .filter((entry): entry is NonNullable<typeof entry> => entry != null);

  if (normalizedPoints.length === 0) return null;

  const geometry: [number, number][] = [];
  const timestampsMs: number[] = [];
  const speeds: number[] = [];
  const statsPoints: TrackPoint[] = [];

  for (const entry of normalizedPoints) {
    const lastCoord = geometry[geometry.length - 1];
    const isDuplicateCoord =
      lastCoord != null &&
      Math.abs(lastCoord[0] - entry.lon) <= EPSILON_DISTANCE &&
      Math.abs(lastCoord[1] - entry.lat) <= EPSILON_DISTANCE;
    const lastTs = timestampsMs[timestampsMs.length - 1];

    // Drop exact duplicate samples to avoid zero-length/duplicate segments.
    if (isDuplicateCoord && lastTs === entry.ts) continue;

    geometry.push([entry.lon, entry.lat]);
    timestampsMs.push(entry.ts);
    speeds.push(entry.speed);
    statsPoints.push(entry.point);
  }

  if (geometry.length === 0) return null;

  const stats = calculateStats(statsPoints);

  return {
    vesselId: `${hints?.sigSrcCd || DEFAULT_SIGNAL_SOURCE}_${mmsi}`,
    targetId: String(mmsi),
    sigSrcCd: hints?.sigSrcCd || DEFAULT_SIGNAL_SOURCE,
    shipName: (hints?.shipName || first.name || '').trim() || `MMSI ${mmsi}`,
    shipKindCode: hints?.shipKindCode || DEFAULT_SHIP_KIND,
    nationalCode: hints?.nationalCode || '',
    geometry,
    timestampsMs,
    speeds,
    stats,
  };
}

export function getTracksTimeRange(tracks: ProcessedTrack[]): { start: number; end: number } | null {
  if (tracks.length === 0) return null;

  let min = Number.POSITIVE_INFINITY;
  let max = Number.NEGATIVE_INFINITY;

  for (const track of tracks) {
    if (track.timestampsMs.length === 0) continue;
    min = Math.min(min, track.timestampsMs[0]);
    max = Math.max(max, track.timestampsMs[track.timestampsMs.length - 1]);
  }

  if (!Number.isFinite(min) || !Number.isFinite(max) || min > max) return null;
  return { start: min, end: max };
}

export function getShipKindColor(shipKindCode: string): [number, number, number, number] {
  const colors: Record<string, [number, number, number, number]> = {
    '000020': [25, 116, 25, 180],
    '000021': [0, 41, 255, 180],
    '000022': [176, 42, 42, 180],
    '000023': [255, 139, 54, 180],
    '000024': [255, 0, 0, 180],
    '000025': [92, 30, 224, 180],
    '000027': [255, 135, 207, 180],
    '000028': [232, 95, 27, 180],
  };

  return colors[shipKindCode] || colors['000027'];
}
