/**
 * Utility class for geographic calculations
 */
export class GeographicUtils {
  /**
   * Check if a point is inside a polygon using ray-casting algorithm
   * @param point - [longitude, latitude]
   * @param polygon - Array of [longitude, latitude] pairs
   */
  static isPointInPolygon(point: [number, number], polygon: [number, number][]): boolean {
    const x = point[0];
    const y = point[1];
    let inside = false;

    for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
      const xi = polygon[i][0];
      const yi = polygon[i][1];
      const xj = polygon[j][0];
      const yj = polygon[j][1];

      const intersect =
        yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi + Number.EPSILON) + xi;
      if (intersect) inside = !inside;
    }

    return inside;
  }

  /**
   * Convert degrees to radians
   */
  private static toRad(value: number): number {
    return (value * Math.PI) / 180;
  }

  /**
   * Calculate distance between two points in kilometers using Haversine formula
   */
  static getDistanceKm(lat1: number, lng1: number, lat2: number, lng2: number): number {
    const R = 6371; // Earth radius in KM

    const dLat = this.toRad(lat2 - lat1);
    const dLng = this.toRad(lng2 - lng1);

    const a =
      Math.sin(dLat / 2) ** 2 +
      Math.cos(this.toRad(lat1)) * Math.cos(this.toRad(lat2)) * Math.sin(dLng / 2) ** 2;

    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return R * c;
  }

  /**
   * Calculate distance between two points in kilometers (rounded)
   */
  static getDistanceKmRounded(
    lat1: number,
    lng1: number,
    lat2: number,
    lng2: number,
    precision = 2,
  ): number {
    const distance = this.getDistanceKm(lat1, lng1, lat2, lng2);
    return Number(distance.toFixed(precision));
  }
}

