// SPDX-FileCopyrightText: 2026 Stan Grams <sjg@haxx.space>
//
// SPDX-License-Identifier: GPL-2.0-or-later

export interface LatLon {
  readonly lat: number;
  readonly lon: number;
}

export function haversineKm(lat1: number, lon1: number, lat2: number, lon2: number): number {
  const radiusKm = 6371;
  const dLat = (lat2 - lat1) * Math.PI / 180;
  const dLon = (lon2 - lon1) * Math.PI / 180;
  const a = Math.sin(dLat / 2) ** 2
    + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon / 2) ** 2;
  return radiusKm * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
}

export function locatorToLatLon(locator: unknown): LatLon | null {
  const raw = typeof locator === "string" ? locator.trim().toUpperCase() : "";
  if (!/^[A-R]{2}\d{2}(?:[A-X]{2})?$/.test(raw)) return null;
  let lon = -180 + (raw.charCodeAt(0) - 65) * 20 + Number(raw.slice(2, 3)) * 2;
  let lat = -90 + (raw.charCodeAt(1) - 65) * 10 + Number(raw.slice(3, 4));
  if (raw.length >= 6) {
    lon += (raw.charCodeAt(4) - 65) * (5 / 60) + 2.5 / 60;
    lat += (raw.charCodeAt(5) - 65) * (2.5 / 60) + 1.25 / 60;
  } else {
    lon += 1;
    lat += 0.5;
  }
  return { lat, lon };
}

export function formatDistanceKm(distanceKm: number): string | null {
  if (!Number.isFinite(distanceKm)) return null;
  return distanceKm < 1 ? `${Math.round(distanceKm * 1000)} m` : `${distanceKm.toFixed(1)} km`;
}

export function formatTimeAgo(timestampMs: number): string | null {
  if (!timestampMs) return null;
  const seconds = Math.round((Date.now() - timestampMs) / 1000);
  if (seconds < 60) return `${seconds}s ago`;
  const minutes = Math.round(seconds / 60);
  if (minutes < 60) return `${minutes} min ago`;
  const hours = Math.floor(minutes / 60);
  const remainingMinutes = minutes % 60;
  return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}min ago` : `${hours}h ago`;
}

export function latLonToMaidenhead(lat: number, lon: number): string {
  const adjustedLon = lon + 180;
  const adjustedLat = lat + 90;
  const upperA = "A".charCodeAt(0);
  const lowerA = "a".charCodeAt(0);
  const field1 = String.fromCharCode(upperA + Math.floor(adjustedLon / 20));
  const field2 = String.fromCharCode(upperA + Math.floor(adjustedLat / 10));
  const square1 = Math.floor((adjustedLon % 20) / 2);
  const square2 = Math.floor(adjustedLat % 10);
  const sub1 = String.fromCharCode(lowerA + Math.floor((adjustedLon % 2) * 12));
  const sub2 = String.fromCharCode(lowerA + Math.floor((adjustedLat % 1) * 24));
  return `${field1}${field2}${square1}${square2}${sub1}${sub2}`;
}
