const getDistance = (p1, p2) => {
  return Math.sqrt(
    Math.pow(p1.longitude - p2.longitude, 2) +
      Math.pow(p1.latitude - p2.latitude, 2)
  );
};

const findNearestPointOnPath = (point, path) => {
  if (!path || path.length < 2) {
    return { index: -1, distance: Infinity, progress: 0 };
  }

  let minDistance = Infinity;
  let bestIndex = -1;
  let bestProgress = 0;

  for (let i = 0; i < path.length - 1; i++) {
    const p1 = { latitude: path[i][0], longitude: path[i][1] };
    const p2 = { latitude: path[i + 1][0], longitude: path[i + 1][1] };

    const dx = p2.longitude - p1.longitude;
    const dy = p2.latitude - p1.latitude;
    const lineLengthSq = dx * dx + dy * dy;

    if (lineLengthSq === 0) continue;

    const t =
      ((point.longitude - p1.longitude) * dx +
        (point.latitude - p1.latitude) * dy) /
      lineLengthSq;
    const projectionT = Math.max(0, Math.min(1, t));

    const projectedX = p1.longitude + projectionT * dx;
    const projectedY = p1.latitude + projectionT * dy;

    const dist = getDistance(
      point,
      { longitude: projectedX, latitude: projectedY }
    );

    if (dist < minDistance) {
      minDistance = dist;
      bestIndex = i;
      bestProgress = projectionT;
    }
  }

  return { index: bestIndex, distance: minDistance, progress: bestProgress };
};

const getStationPositionOnPath = (station, path) => {
  const result = findNearestPointOnPath(
    { latitude: station.latitude, longitude: station.longitude },
    path
  );
  return result.index + result.progress;
};

export const orderStationsByRoute = (stations, routePath, startStopId, endStopId) => {
  if (!stations || !routePath || stations.length === 0 || routePath.length === 0) {
    return stations || [];
  }

  const startStation = stations.find(
    (s) => String(s.id) === String(startStopId)
  );
  const endStation = stations.find(
    (s) => String(s.id) === String(endStopId)
  );

  if (!startStation || !endStation) {
    console.warn("Не найдены начальная или конечная остановки");
    return stations;
  }

  const stationsWithPosition = stations.map((station) => ({
    station,
    position: getStationPositionOnPath(station, routePath),
  }));

  stationsWithPosition.sort((a, b) => a.position - b.position);

  const startPosition = stationsWithPosition.find(
    (s) => s.station.id === startStation.id
  )?.position;
  const endPosition = stationsWithPosition.find(
    (s) => s.station.id === endStation.id
  )?.position;

  if (startPosition > endPosition) {
    stationsWithPosition.reverse();
  }

  return stationsWithPosition.map((item) => item.station);
};

export const getNextStation = (currentPosition, orderedStations, currentStationId = null) => {
  if (!orderedStations || orderedStations.length === 0 || !currentPosition) {
    return null;
  }

  let currentIndex = -1;
  if (currentStationId) {
    currentIndex = orderedStations.findIndex(
      (s) => String(s.id) === String(currentStationId)
    );
  }

  if (currentIndex >= 0 && currentIndex < orderedStations.length - 1) {
    return orderedStations[currentIndex + 1];
  }

  if (currentIndex < 0) {
    let nearestIndex = -1;
    let minDistance = Infinity;

    for (let i = 0; i < orderedStations.length; i++) {
      const distance = getDistance(currentPosition, {
        latitude: orderedStations[i].latitude,
        longitude: orderedStations[i].longitude,
      });
      if (distance < minDistance) {
        minDistance = distance;
        nearestIndex = i;
      }
    }

    if (nearestIndex >= 0) {
      const nearestStation = orderedStations[nearestIndex];
      const nextStation = orderedStations[nearestIndex + 1];

      if (nextStation) {
        const distanceToNearest = getDistance(currentPosition, {
          latitude: nearestStation.latitude,
          longitude: nearestStation.longitude,
        });
        const distanceToNext = getDistance(currentPosition, {
          latitude: nextStation.latitude,
          longitude: nextStation.longitude,
        });

        if (distanceToNext < distanceToNearest) {
          return nextStation;
        }
      }

      if (nearestIndex < orderedStations.length - 1) {
        return orderedStations[nearestIndex + 1];
      }
    }
  }

  return null;
};

export const getTargetStation = (currentPosition, orderedStations, routePath) => {
  if (!orderedStations || orderedStations.length === 0 || !currentPosition || !routePath || routePath.length < 2) {
    return null;
  }

  let nearestIndex = -1;
  let minDistance = Infinity;

  for (let i = 0; i < orderedStations.length; i++) {
    const distance = getDistance(currentPosition, {
      latitude: orderedStations[i].latitude,
      longitude: orderedStations[i].longitude,
    });
    if (distance < minDistance) {
      minDistance = distance;
      nearestIndex = i;
    }
  }

  if (nearestIndex < 0) {
    return null;
  }

  const nearestStation = orderedStations[nearestIndex];
  const nextStation = orderedStations[nearestIndex + 1];

  const tramPosition = findNearestPointOnPath(currentPosition, routePath);
  const tramPosOnRoute = tramPosition.index + tramPosition.progress;

  const stationPosition = findNearestPointOnPath(
    { latitude: nearestStation.latitude, longitude: nearestStation.longitude },
    routePath
  );
  const stationPosOnRoute = stationPosition.index + stationPosition.progress;

  if (tramPosOnRoute > stationPosOnRoute && nextStation) {
    return nextStation;
  }

  return nearestStation;
};

