/**
 * Utility functions for Polyline
 */

export interface LatLng {
  latitude: number;
  longitude: number;
}

/**
 * Tìm điểm ở giữa của polyline
 */
export const getMiddlePointOfPolyline = (coordinates: LatLng[]): LatLng => {
  if (coordinates.length === 0) {
    return { latitude: 0, longitude: 0 };
  }

  if (coordinates.length === 1) {
    return coordinates[0];
  }

  const middleIndex = Math.floor(coordinates.length / 2);
  return coordinates[middleIndex];
};

/**
 * Tính toán điểm ở giữa của 2 điểm
 */
export const getMidpoint = (point1: LatLng, point2: LatLng): LatLng => {
  return {
    latitude: (point1.latitude + point2.latitude) / 2,
    longitude: (point1.longitude + point2.longitude) / 2,
  };
};

/**
 * Tính khoảng cách giữa 2 điểm (Haversine formula)
 * Trả về khoảng cách theo km
 */
export const calculateDistance = (point1: LatLng, point2: LatLng): number => {
  const R = 6371; // Bán kính trái đất (km)
  const dLat = (point2.latitude - point1.latitude) * (Math.PI / 180);
  const dLon = (point2.longitude - point1.longitude) * (Math.PI / 180);
  const a =
    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
    Math.cos(point1.latitude * (Math.PI / 180)) *
      Math.cos(point2.latitude * (Math.PI / 180)) *
      Math.sin(dLon / 2) *
      Math.sin(dLon / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c;
};

/**
 * Tính tổng khoảng cách của polyline
 */
export const calculateTotalDistance = (coordinates: LatLng[]): number => {
  if (coordinates.length < 2) return 0;

  let totalDistance = 0;
  for (let i = 0; i < coordinates.length - 1; i++) {
    totalDistance += calculateDistance(coordinates[i], coordinates[i + 1]);
  }

  return totalDistance;
};

/**
 * Tính heading (hướng) giữa 2 điểm
 * Trả về góc độ (0-360)
 */
export const calculateHeading = (point1: LatLng, point2: LatLng): number => {
  const dLon = point2.longitude - point1.longitude;
  const lat1 = point1.latitude * (Math.PI / 180);
  const lat2 = point2.latitude * (Math.PI / 180);
  const dLonRad = dLon * (Math.PI / 180);

  const y = Math.sin(dLonRad) * Math.cos(lat2);
  const x =
    Math.cos(lat1) * Math.sin(lat2) -
    Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLonRad);

  const bearing = Math.atan2(y, x) * (180 / Math.PI);
  return (bearing + 360) % 360;
};

/**
 * Tính điểm trung tâm (centroid) của polygon
 * Sử dụng thuật toán Shoelace formula để tính centroid chính xác
 * Thuật toán này tính centroid dựa trên diện tích, phù hợp với polygon bất kỳ
 */
export const getPolygonCenter = (coordinates: LatLng[]): LatLng => {
  if (coordinates.length === 0) {
    return { latitude: 0, longitude: 0 };
  }

  if (coordinates.length === 1) {
    return coordinates[0];
  }

  if (coordinates.length === 2) {
    return {
      latitude: (coordinates[0].latitude + coordinates[1].latitude) / 2,
      longitude: (coordinates[0].longitude + coordinates[1].longitude) / 2,
    };
  }

  let area = 0;
  let centroidLat = 0;
  let centroidLon = 0;

  // Đảm bảo polygon đóng (điểm đầu = điểm cuối)
  const coords = [...coordinates];
  if (
    coords[0].latitude !== coords[coords.length - 1].latitude ||
    coords[0].longitude !== coords[coords.length - 1].longitude
  ) {
    coords.push(coords[0]);
  }

  // Tính diện tích và centroid sử dụng Shoelace formula
  for (let i = 0; i < coords.length - 1; i++) {
    const lat1 = coords[i].latitude;
    const lon1 = coords[i].longitude;
    const lat2 = coords[i + 1].latitude;
    const lon2 = coords[i + 1].longitude;

    const cross = lat1 * lon2 - lon1 * lat2;
    area += cross;
    centroidLat += (lat1 + lat2) * cross;
    centroidLon += (lon1 + lon2) * cross;
  }

  area = area / 2;

  // Nếu diện tích quá nhỏ (polygon suy biến), dùng trung bình đơn giản
  if (Math.abs(area) < 0.0000001) {
    let latSum = 0;
    let lonSum = 0;
    for (const coord of coordinates) {
      latSum += coord.latitude;
      lonSum += coord.longitude;
    }
    return {
      latitude: latSum / coordinates.length,
      longitude: lonSum / coordinates.length,
    };
  }

  centroidLat = centroidLat / (6 * area);
  centroidLon = centroidLon / (6 * area);

  return {
    latitude: centroidLat,
    longitude: centroidLon,
  };
};
