package com.bonus.system.att.utils;

import java.util.Locale;

public class DistanceCalculator {

    // 地球半径（单位：公里）
    private static final double EARTH_RADIUS_KM = 6371.0;
    // 地球半径（单位：英里）
    private static final double EARTH_RADIUS_MILES = 3958.8;
    // 地球半径（单位：米）
    private static final double EARTH_RADIUS_METERS = EARTH_RADIUS_KM * 1000.0;

    /**
     * 计算两点之间的距离（单位：公里）
     *
     * @param lat1 第一个点的纬度
     * @param lon1 第一个点的经度
     * @param lat2 第二个点的纬度
     * @param lon2 第二个点的经度
     * @return 两点之间的距离（单位：公里）
     */
    public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        return calculateDistance(lat1, lon1, lat2, lon2, Unit.KILOMETERS);
    }

    /**
     * 计算两点之间的距离
     *
     * @param lat1  第一个点的纬度
     * @param lon1  第一个点的经度
     * @param lat2  第二个点的纬度
     * @param lon2  第二个点的经度
     * @param unit  距离单位（公里、英里或米）
     * @return 两点之间的距离
     */
    /**
     * 计算两个地理坐标之间的距离。
     *
     * @param lat1 第一个坐标的纬度
     * @param lon1 第一个坐标的经度
     * @param lat2 第二个坐标的纬度
     * @param lon2 第二个坐标的经度
     * @param unit  距离单位（KILOMETERS, MILES, METERS）
     * @return 两个坐标之间的距离，如果输入无效则返回 1000000
     */
    public static double calculateDistance(Double lat1, Double lon1, Double lat2, Double lon2, Unit unit) {
        // 检查输入是否为空
        if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) {
            return 1000000;
        }

        // 检查纬度和经度是否在合理范围内
        if (!isValidLatitude(lat1) || !isValidLongitude(lon1) ||
                !isValidLatitude(lat2) || !isValidLongitude(lon2)) {
            return 1000000;
        }

        // 将纬度和经度从度转换为弧度
        double lat1Rad = Math.toRadians(lat1);
        double lon1Rad = Math.toRadians(lon1);
        double lat2Rad = Math.toRadians(lat2);
        double lon2Rad = Math.toRadians(lon2);

        // Haversine 公式
        double dLat = lat2Rad - lat1Rad;
        double dLon = lon2Rad - lon1Rad;
        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(lat1Rad) * Math.cos(lat2Rad) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        // 计算距离
        double distance;
        switch (unit) {
            case KILOMETERS:
                distance = EARTH_RADIUS_KM * c;
                break;
            case MILES:
                distance = EARTH_RADIUS_MILES * c;
                break;
            case METERS:
                distance = EARTH_RADIUS_METERS * c;
                break;
            default:
                throw new IllegalArgumentException("Unsupported unit: " + unit);
        }
        return distance;
    }

    /**
     * 检查纬度是否在 -90 到 90 之间。
     *
     * @param lat 纬度
     * @return 如果纬度有效返回 true，否则返回 false
     */
    private static boolean isValidLatitude(double lat) {
        return lat >= -90 && lat <= 90;
    }

    /**
     * 检查经度是否在 -180 到 180 之间。
     *
     * @param lon 经度
     * @return 如果经度有效返回 true，否则返回 false
     */
    private static boolean isValidLongitude(double lon) {
        return lon >= -180 && lon <= 180;
    }

    /**
     * 距离单位枚举
     */
    public enum Unit {
        KILOMETERS,
        MILES,
        METERS
    }

    /**
     * 测试方法
     */
    public static void main(String[] args) {
        // 示例：计算北京 (39.9042, 116.4074) 和上海 (31.2304, 121.4737) 之间的距离
        double lat1 = 39.9042;
        double lon1 = 116.4074;
        double lat2 = 31.2304;
        double lon2 = 121.4737;

        double distanceKm = calculateDistance(lat1, lon1, lat2, lon2, Unit.KILOMETERS);
        double distanceMiles = calculateDistance(lat1, lon1, lat2, lon2, Unit.MILES);
        double distanceMeters = calculateDistance(lat1, lon1, lat2, lon2, Unit.METERS);

        System.out.printf(Locale.US, "Distance between Beijing and Shanghai: %.2f km\n", distanceKm);
        System.out.printf(Locale.US, "Distance between Beijing and Shanghai: %.2f miles\n", distanceMiles);
        System.out.printf(Locale.US, "Distance between Beijing and Shanghai: %.2f meters\n", distanceMeters);
    }
}
