package com.ghy.common.utils;

/**
 * 地理位置计算工具类
 * 提供经纬度之间的距离计算功能
 * 
 * @author clunt
 */
public class LocationUtils {
    
    /** 地球半径（千米） */
    private static final double EARTH_RADIUS_KM = 6371.0;
    
    /** 地球半径（米） */
    private static final double EARTH_RADIUS_M = 6371000.0;
    
    /**
     * 使用Haversine公式计算两点间的距离（米）
     * 
     * @param lat1 第一个点的纬度
     * @param lng1 第一个点的经度
     * @param lat2 第二个点的纬度
     * @param lng2 第二个点的经度
     * @return 距离（米）
     */
    public static double getDistanceInMeters(double lat1, double lng1, double lat2, double lng2) {
        return getDistanceInKilometers(lat1, lng1, lat2, lng2) * 1000;
    }
    
    /**
     * 使用Haversine公式计算两点间的距离（千米）
     * 
     * @param lat1 第一个点的纬度
     * @param lng1 第一个点的经度
     * @param lat2 第二个点的纬度
     * @param lng2 第二个点的经度
     * @return 距离（千米）
     */
    public static double getDistanceInKilometers(double lat1, double lng1, double lat2, double lng2) {
        // 将角度转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lng1Rad = Math.toRadians(lng1);
        double lat2Rad = Math.toRadians(lat2);
        double lng2Rad = Math.toRadians(lng2);
        
        // 计算经纬度差值
        double deltaLat = lat2Rad - lat1Rad;
        double deltaLng = lng2Rad - lng1Rad;
        
        // Haversine公式
        double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
                   Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                   Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2);
        
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        
        return EARTH_RADIUS_KM * c;
    }
    
    /**
     * 判断某个点是否在指定范围内
     * 
     * @param centerLat 中心点纬度
     * @param centerLng 中心点经度
     * @param targetLat 目标点纬度
     * @param targetLng 目标点经度
     * @param radiusKm 半径（千米）
     * @return 是否在范围内
     */
    public static boolean isWithinRadius(double centerLat, double centerLng, 
                                       double targetLat, double targetLng, 
                                       double radiusKm) {
        double distance = getDistanceInKilometers(centerLat, centerLng, targetLat, targetLng);
        return distance <= radiusKm;
    }
    
    /**
     * 格式化距离显示
     * 
     * @param distanceInMeters 距离（米）
     * @return 格式化后的距离字符串
     */
    public static String formatDistance(double distanceInMeters) {
        if (distanceInMeters < 1000) {
            return String.format("%.0f米", distanceInMeters);
        } else {
            double km = distanceInMeters / 1000;
            if (km < 10) {
                return String.format("%.1f公里", km);
            } else {
                return String.format("%.0f公里", km);
            }
        }
    }
    
    /**
     * 计算两个坐标点的方位角（以正北为0度，顺时针）
     * 
     * @param lat1 起点纬度
     * @param lng1 起点经度
     * @param lat2 终点纬度
     * @param lng2 终点经度
     * @return 方位角（度数，0-360）
     */
    public static double getBearing(double lat1, double lng1, double lat2, double lng2) {
        double lat1Rad = Math.toRadians(lat1);
        double lat2Rad = Math.toRadians(lat2);
        double deltaLngRad = Math.toRadians(lng2 - lng1);
        
        double y = Math.sin(deltaLngRad) * Math.cos(lat2Rad);
        double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) - 
                   Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(deltaLngRad);
        
        double bearingRad = Math.atan2(y, x);
        double bearingDeg = Math.toDegrees(bearingRad);
        
        // 转换为0-360度
        return (bearingDeg + 360) % 360;
    }
    
    /**
     * 将方位角转换为方向描述
     * 
     * @param bearing 方位角（度数）
     * @return 方向描述
     */
    public static String getDirectionDescription(double bearing) {
        String[] directions = {"北", "东北", "东", "东南", "南", "西南", "西", "西北"};
        int index = (int) Math.round(bearing / 45) % 8;
        return directions[index];
    }
    
    /**
     * 验证经纬度的有效性
     * 
     * @param latitude 纬度
     * @param longitude 经度
     * @return 是否有效
     */
    public static boolean isValidCoordinate(Double latitude, Double longitude) {
        if (latitude == null || longitude == null) {
            return false;
        }
        return latitude >= -90 && latitude <= 90 && longitude >= -180 && longitude <= 180;
    }
    
    /**
     * 计算中心点坐标（多个点的几何中心）
     * 
     * @param coordinates 坐标点数组，每个元素为[纬度, 经度]
     * @return 中心点坐标 [纬度, 经度]
     */
    public static double[] getCenterPoint(double[][] coordinates) {
        if (coordinates == null || coordinates.length == 0) {
            return null;
        }
        
        double sumLat = 0, sumLng = 0;
        for (double[] coord : coordinates) {
            sumLat += coord[0];
            sumLng += coord[1];
        }
        
        return new double[]{sumLat / coordinates.length, sumLng / coordinates.length};
    }
} 