/**
 * Privacy utilities for rMaps: location fuzzing, distance calculations, formatting.
 */

import type { PrecisionLevel } from "./map-sync";

/** Noise radius in meters per precision level */
const PRECISION_RADIUS: Record<PrecisionLevel, number> = {
	exact: 0,
	building: 50,
	area: 500,
	approximate: 5000,
	hidden: Infinity,
};

/**
 * Add random noise to coordinates based on precision level.
 * Returns original coords if precision is "exact".
 */
export function fuzzLocation(lat: number, lng: number, precision: PrecisionLevel): { latitude: number; longitude: number } {
	const radius = PRECISION_RADIUS[precision];
	if (radius === 0) return { latitude: lat, longitude: lng };

	// Random angle and distance within radius
	const angle = Math.random() * 2 * Math.PI;
	const dist = Math.random() * radius;

	// Approximate meters to degrees
	const dLat = (dist * Math.cos(angle)) / 111320;
	const dLng = (dist * Math.sin(angle)) / (111320 * Math.cos(lat * (Math.PI / 180)));

	return {
		latitude: lat + dLat,
		longitude: lng + dLng,
	};
}

/**
 * Haversine distance between two points in meters.
 */
export function haversineDistance(lat1: number, lng1: number, lat2: number, lng2: number): number {
	const R = 6371000; // Earth radius in meters
	const toRad = (d: number) => d * (Math.PI / 180);

	const dLat = toRad(lat2 - lat1);
	const dLng = toRad(lng2 - lng1);
	const a =
		Math.sin(dLat / 2) ** 2 +
		Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
	const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

	return R * c;
}

/**
 * Format a distance in meters to a human-readable string.
 */
export function formatDistance(meters: number): string {
	if (meters < 50) return "nearby";
	if (meters < 1000) return `${Math.round(meters)}m`;
	if (meters < 10000) return `${(meters / 1000).toFixed(1)}km`;
	return `${Math.round(meters / 1000)}km`;
}

/**
 * Format seconds to a human-readable duration.
 */
export function formatTime(seconds: number): string {
	if (seconds < 60) return `${Math.round(seconds)}s`;
	const m = Math.floor(seconds / 60);
	if (m < 60) return `${m} min`;
	const h = Math.floor(m / 60);
	const rm = m % 60;
	return rm > 0 ? `${h}h ${rm}m` : `${h}h`;
}
