import type { GalaxyConnection, GalaxySystem, NavigationRoute, RouteSegment } from "./types";

const distanceBetween = (a: GalaxySystem, b: GalaxySystem) => {
  const dx = a.x - b.x;
  const dy = a.y - b.y;
  const dz = a.z - b.z;
  return Math.sqrt(dx * dx + dy * dy + dz * dz);
};

export function findShortestRoute(
  originId: string,
  destinationId: string,
  systems: GalaxySystem[],
  connections: GalaxyConnection[],
): NavigationRoute | null {
  const byId = new Map(systems.map((system) => [system.id, system]));
  const origin = byId.get(originId);
  const destination = byId.get(destinationId);
  if (!origin || !destination) return null;

  if (originId === destinationId) {
    return { origin, destination, systems: [origin], segments: [], totalDistance: 0 };
  }

  const graph = new Map<string, string[]>();
  for (const system of systems) graph.set(system.id, []);
  for (const [a, b] of connections) {
    graph.get(a)?.push(b);
    graph.get(b)?.push(a);
  }

  const queue = [originId];
  const previous = new Map<string, string | null>([[originId, null]]);
  for (let i = 0; i < queue.length; i += 1) {
    const current = queue[i];
    if (current === destinationId) break;
    for (const next of graph.get(current) ?? []) {
      if (previous.has(next)) continue;
      previous.set(next, current);
      queue.push(next);
    }
  }

  if (!previous.has(destinationId)) return null;

  const ids: string[] = [];
  let cursor: string | null = destinationId;
  while (cursor) {
    ids.unshift(cursor);
    cursor = previous.get(cursor) ?? null;
  }

  const routeSystems = ids.map((id) => byId.get(id)).filter(Boolean) as GalaxySystem[];
  const segments: RouteSegment[] = [];
  for (let i = 0; i < routeSystems.length - 1; i += 1) {
    const from = routeSystems[i];
    const to = routeSystems[i + 1];
    segments.push({ from, to, distance: distanceBetween(from, to) });
  }

  return {
    origin,
    destination,
    systems: routeSystems,
    segments,
    totalDistance: segments.reduce((sum, segment) => sum + segment.distance, 0),
  };
}

export function combineRoutes(routes: Array<NavigationRoute | null>): NavigationRoute | null {
  const valid = routes.filter(Boolean) as NavigationRoute[];
  if (valid.length === 0) return null;
  const systems: GalaxySystem[] = [];
  const segments: RouteSegment[] = [];
  for (const route of valid) {
    route.systems.forEach((system, index) => {
      if (systems.length === 0 || index > 0) systems.push(system);
    });
    segments.push(...route.segments);
  }
  return {
    origin: systems[0],
    destination: systems[systems.length - 1],
    systems,
    segments,
    totalDistance: segments.reduce((sum, segment) => sum + segment.distance, 0),
  };
}
