import { haversineDistance, calculateCentroid, parseGeoJsonPolygon } from '../../../utils/spatial';

export interface RouteLocation {
  id: string;
  latitude: number;
  longitude: number;
}

export interface RouteResult {
  orderedLocations: RouteLocation[];
  totalDistanceMeters: number;
  estimatedMinutes: number;
}

const WALKING_SPEED_MPS = 5000 / 60; // 5 km/h in meters per minute
const MINUTES_PER_DOOR = 2;

/**
 * Nearest-neighbor walking route algorithm.
 * Starts from volunteer GPS position or cut polygon centroid.
 */
export function calculateWalkingRoute(
  locations: RouteLocation[],
  startLat?: number,
  startLng?: number,
  cutGeojson?: string,
): RouteResult {
  if (locations.length === 0) {
    return { orderedLocations: [], totalDistanceMeters: 0, estimatedMinutes: 0 };
  }

  // Determine starting point
  let currentLat: number;
  let currentLng: number;

  if (startLat !== undefined && startLng !== undefined) {
    currentLat = startLat;
    currentLng = startLng;
  } else if (cutGeojson) {
    const polygons = parseGeoJsonPolygon(cutGeojson);
    const centroid = calculateCentroid(polygons[0]!);
    currentLat = centroid.lat;
    currentLng = centroid.lng;
  } else {
    // Use first location as starting point
    currentLat = locations[0]!.latitude;
    currentLng = locations[0]!.longitude;
  }

  const remaining = [...locations];
  const ordered: RouteLocation[] = [];
  let totalDistance = 0;

  while (remaining.length > 0) {
    let nearestIdx = 0;
    let nearestDist = Infinity;

    for (let i = 0; i < remaining.length; i++) {
      const loc = remaining[i]!;
      const dist = haversineDistance(currentLat, currentLng, loc.latitude, loc.longitude);
      if (dist < nearestDist) {
        nearestDist = dist;
        nearestIdx = i;
      }
    }

    const nearest = remaining.splice(nearestIdx, 1)[0]!;
    ordered.push(nearest);
    totalDistance += nearestDist;
    currentLat = nearest.latitude;
    currentLng = nearest.longitude;
  }

  const walkingMinutes = totalDistance / WALKING_SPEED_MPS;
  const doorMinutes = ordered.length * MINUTES_PER_DOOR;
  const estimatedMinutes = Math.round(walkingMinutes + doorMinutes);

  return {
    orderedLocations: ordered,
    totalDistanceMeters: Math.round(totalDistance),
    estimatedMinutes,
  };
}
