package com.grigowashere.aismap.utils;

/**
 * Утилиты для навигационных вычислений
 */
public class NavigationUtils {
    
    // Радиус Земли в метрах
    private static final double EARTH_RADIUS_METERS = 6371000.0;
    
    /**
     * Вычисляет расстояние между двумя точками на Земле (формула гаверсинуса)
     * @param lat1 широта первой точки в градусах
     * @param lon1 долгота первой точки в градусах
     * @param lat2 широта второй точки в градусах
     * @param lon2 долгота второй точки в градусах
     * @return расстояние в метрах
     */
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        // Проверяем валидность координат
        if (lat1 == 0 && lon1 == 0) return -1;
        if (lat2 == 0 && lon2 == 0) return -1;
        
        // Преобразуем градусы в радианы
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);
        
        // Разности координат
        double deltaLat = lat2Rad - lat1Rad;
        double deltaLon = lon2Rad - lon1Rad;
        
        // Формула гаверсинуса
        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                   Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                   Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return EARTH_RADIUS_METERS * c;
    }
    
    /**
     * Вычисляет азимут (bearing) от первой точки ко второй
     * @param lat1 широта первой точки в градусах
     * @param lon1 долгота первой точки в градусах
     * @param lat2 широта второй точки в градусах
     * @param lon2 долгота второй точки в градусах
     * @return азимут в градусах (0-360)
     */
    public static double calculateBearing(double lat1, double lon1, double lat2, double lon2) {
        // Проверяем валидность координат
        if (lat1 == 0 && lon1 == 0) return -1;
        if (lat2 == 0 && lon2 == 0) return -1;
        
        // Преобразуем градусы в радианы
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);
        
        // Разности координат
        double deltaLon = lon2Rad - lon1Rad;
        
        // Вычисляем азимут
        double y = Math.sin(deltaLon) * Math.cos(lat2Rad);
        double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - 
                   Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLon);
        
        double bearingRad = Math.atan2(y, x);
        double bearingDeg = Math.toDegrees(bearingRad);
        
        // Нормализуем к диапазону 0-360
        return (bearingDeg + 360) % 360;
    }
    
    /**
     * Вычисляет относительный азимут (сколько градусов влево/вправо от нашего курса)
     * @param ourCourse наш курс в градусах (0-360)
     * @param targetBearing азимут до цели в градусах (0-360)
     * @return относительный азимут в градусах (-180 до +180, отрицательное = влево, положительное = вправо)
     */
    public static double calculateRelativeBearing(double ourCourse, double targetBearing) {
        if (ourCourse < 0 || targetBearing < 0) return -1;
        
        double relativeBearing = targetBearing - ourCourse;
        
        // Нормализуем к диапазону -180 до +180
        while (relativeBearing > 180) relativeBearing -= 360;
        while (relativeBearing < -180) relativeBearing += 360;
        
        return relativeBearing;
    }
    
    /**
     * Форматирует расстояние для отображения
     * @param distanceMeters расстояние в метрах
     * @return отформатированная строка
     */
    public static String formatDistance(double distanceMeters) {
        if (distanceMeters < 0) return "--";
        
        if (distanceMeters < 1000) {
            return String.format("%.0f м", distanceMeters);
        } else {
            return String.format("%.1f км", distanceMeters / 1000.0);
        }
    }
    
    /**
     * Форматирует относительный азимут для отображения
     * @param relativeBearing относительный азимут в градусах
     * @return отформатированная строка
     */
    public static String formatRelativeBearing(double relativeBearing) {
        // Проверяем на невалидные значения
        if (relativeBearing < -180 || relativeBearing > 180) return "--";
        
        if (Math.abs(relativeBearing) < 1) {
            return "прямо";
        } else if (relativeBearing > 0) {
            return String.format("%.0f° вправо", relativeBearing);
        } else {
            return String.format("%.0f° влево", Math.abs(relativeBearing));
        }
    }
}
