import 'dart:math' as math;

class DistanceCalculator {
  static const double earthRadiusKm = 6371.0;

  static double calculateDistance({
    required double lat1,
    required double lon1,
    required double lat2,
    required double lon2,
  }) {
    final double dLat = _toRadians(lat2 - lat1);
    final double dLon = _toRadians(lon2 - lon1);

    final double a =
        math.sin(dLat / 2) * math.sin(dLat / 2) +
        math.cos(_toRadians(lat1)) *
            math.cos(_toRadians(lat2)) *
            math.sin(dLon / 2) *
            math.sin(dLon / 2);

    final double c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));

    return earthRadiusKm * c;
  }

  static double _toRadians(double degree) {
    return degree * (math.pi / 180);
  }

  static String formatDistance(double distanceInKm) {
    if (distanceInKm < 1) {
      return '${(distanceInKm * 1000).round()}m';
    } else if (distanceInKm < 10) {
      return '${distanceInKm.toStringAsFixed(1)}km';
    } else {
      return '${distanceInKm.round()}km';
    }
  }

  static bool isWithinDistance({
    required double lat1,
    required double lon1,
    required double lat2,
    required double lon2,
    required double maxDistanceKm,
  }) {
    final distance = calculateDistance(
      lat1: lat1,
      lon1: lon1,
      lat2: lat2,
      lon2: lon2,
    );
    return distance <= maxDistanceKm;
  }

  static double? calculateDistanceFromCurrentLocation({
    required double targetLat,
    required double targetLon,
    double? currentLat,
    double? currentLon,
  }) {
    if (currentLat == null || currentLon == null) {
      return null;
    }

    return calculateDistance(
      lat1: currentLat,
      lon1: currentLon,
      lat2: targetLat,
      lon2: targetLon,
    );
  }

  static List<T> sortByDistance<T>({
    required List<T> items,
    required double Function(T) getLat,
    required double Function(T) getLon,
    required double currentLat,
    required double currentLon,
  }) {
    final List<T> sortedItems = List<T>.from(items);

    sortedItems.sort((a, b) {
      final distanceA = calculateDistance(
        lat1: currentLat,
        lon1: currentLon,
        lat2: getLat(a),
        lon2: getLon(a),
      );

      final distanceB = calculateDistance(
        lat1: currentLat,
        lon1: currentLon,
        lat2: getLat(b),
        lon2: getLon(b),
      );

      return distanceA.compareTo(distanceB);
    });

    return sortedItems;
  }

  static Map<String, double> getDefaultLocationForKorea() {
    return {'latitude': 37.5665, 'longitude': 126.9780};
  }
}
