package com.grigowashere.aismap.utils;

import com.grigowashere.aismap.models.AISVessel;
import com.grigowashere.aismap.models.Vessel;

/**
 * Утилиты для геодезических расчетов
 */
public class GeoUtils {
    
    private static final double EARTH_RADIUS = 6371000; // радиус Земли в метрах
    
    /**
     * Рассчитывает расстояние между двумя точками по формуле гаверсинуса
     * @param lat1 широта первой точки в градусах
     * @param lon1 долгота первой точки в градусах
     * @param lat2 широта второй точки в градусах
     * @param lon2 долгота второй точки в градусах
     * @return расстояние в метрах
     */
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        double lat1Rad = Math.toRadians(lat1);
        double lat2Rad = Math.toRadians(lat2);
        double deltaLat = Math.toRadians(lat2 - lat1);
        double deltaLon = Math.toRadians(lon2 - lon1);
        
        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 * c;
    }
    
    /**
     * Рассчитывает расстояние от нашего судна до AIS судна
     * @param ourVessel наше судно
     * @param aisVessel AIS судно
     * @return расстояние в метрах
     */
    public static double calculateDistance(Vessel ourVessel, AISVessel aisVessel) {
        return calculateDistance(
            ourVessel.getLatitude(), ourVessel.getLongitude(),
            aisVessel.getLatitude(), aisVessel.getLongitude()
        );
    }
    
    /**
     * Рассчитывает пеленг от первой точки ко второй
     * @param lat1 широта первой точки в градусах
     * @param lon1 долгота первой точки в градусах
     * @param lat2 широта второй точки в градусах
     * @param lon2 долгота второй точки в градусах
     * @return пеленг в градусах (0-360)
     */
    public static double calculateBearing(double lat1, double lon1, double lat2, double lon2) {
        double lat1Rad = Math.toRadians(lat1);
        double lat2Rad = Math.toRadians(lat2);
        double deltaLon = Math.toRadians(lon2 - lon1);
        
        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 bearing = Math.toDegrees(Math.atan2(y, x));
        return (bearing + 360) % 360; // нормализуем к диапазону 0-360
    }
    
    /**
     * Рассчитывает пеленг от нашего судна до AIS судна
     * @param ourVessel наше судно
     * @param aisVessel AIS судно
     * @return пеленг в градусах (0-360)
     */
    public static double calculateBearing(Vessel ourVessel, AISVessel aisVessel) {
        return calculateBearing(
            ourVessel.getLatitude(), ourVessel.getLongitude(),
            aisVessel.getLatitude(), aisVessel.getLongitude()
        );
    }
    
    /**
     * Конвертирует навигационный статус в числовой код
     * @param navigationalStatus строковый статус
     * @return числовой код статуса
     */
    public static int getNavigationStatusCode(String navigationalStatus) {
        if (navigationalStatus == null) return -1;
        
        switch (navigationalStatus.toLowerCase()) {
            case "under way using engine":
            case "under way":
                return 0;
            case "at anchor":
            case "anchored":
                return 1;
            case "not under command":
                return 2;
            case "restricted manoeuvrability":
                return 3;
            case "constrained by her draught":
                return 4;
            case "moored":
                return 5;
            case "aground":
                return 6;
            case "engaged in fishing":
                return 7;
            case "under way sailing":
                return 8;
            default:
                return -1;
        }
    }
}
