import {
  formatInventory,
  formatLocalDistance,
  formatShipSpeed,
  formatSystemDistance,
  inventoryAmount,
} from "./viewerMath";
import { usePlayerFactionStore } from "./ui/stores/playerFactionStore";
import { viewerPinia } from "./ui/stores/pinia";
import { getShipOrderLabel } from "./shipAutomationPresentation";
import modulesData from "../../../shared/data/modules.json";
import itemsData from "../../../shared/data/items.json";

const moduleNameById = new Map<string, string>(
  (modulesData as { id: string; name: string }[]).map((m) => [m.id, m.name]),
);
const moduleProductionById = new Map<string, {
  cycleSeconds: number;
  inputs: { itemId: string; amount: number }[];
  outputs: { itemId: string; amount: number }[];
}>(
  (modulesData as { id: string; product?: string[] }[])
    .flatMap((module) => {
      const productItemId = module.product?.[0];
      if (!productItemId) {
        return [];
      }

      const item = (itemsData as {
        id: string;
        production?: { time: number; amount: number; method?: string; wares?: { ware?: string; itemId?: string; amount: number }[] }[];
      }[]).find((candidate) => candidate.id === productItemId);
      const production = item?.production?.find((recipe) => (recipe.method ?? "default") === "default")
        ?? item?.production?.[0];
      if (!production) {
        return [];
      }

      return [[module.id, {
        cycleSeconds: production.time,
        inputs: (production.wares ?? []).map((ware) => ({
          itemId: ware.ware ?? ware.itemId ?? "unknown",
          amount: ware.amount,
        })),
        outputs: [{
          itemId: productItemId,
          amount: production.amount,
        }],
      }] as const];
    }),
);
const itemTransportById = new Map<string, string>(
  (itemsData as { id: string; transport: string }[]).map((item) => [item.id, item.transport]),
);
import { describeCelestialPathWithinSystem, describeOrbitalParent, describeSelectable, describeShipBehavior, describeShipCurrentAction, describeShipOrder, describeShipState, getSelectionGroup, renderSystemDetails } from "./viewerSelection";
import type {
  CameraMode,
  NodeVisual,
  OrbitalAnchor,
  Selectable,
  ShipVisual,
  StructureVisual,
  WorldState,
} from "./viewerTypes";

interface DetailPanelParams {
  world: WorldState;
  selectedItems: Selectable[];
  povLevel: string;
  cameraMode: CameraMode;
  cameraTargetShipId?: string;
  worldLabel: string;
  describeSelectionParent: (selection: Selectable) => string;
}

interface SystemPanelParams {
  world: WorldState;
  activeSystemId?: string;
  cameraMode: CameraMode;
  cameraTargetShipId?: string;
}

function formatDuration(seconds: number): string {
  if (seconds < 60) return `${Math.ceil(seconds)}s`;
  const m = Math.floor(seconds / 60);
  const s = Math.ceil(seconds % 60);
  return s > 0 ? `${m}m ${s}s` : `${m}m`;
}


function escapeAttr(str: string): string {
  return str
    .replaceAll("&", "&amp;")
    .replaceAll("\"", "&quot;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;");
}

function renderProgressBar(progress: number): string {
  return `<div class="detail-progress"><div class="detail-progress-track"><div class="detail-progress-fill" style="width: ${(progress * 100).toFixed(1)}%"></div></div></div>`;
}

function buildStaticModuleTooltip(world: WorldState, stationId: string, moduleId: string): string | null {
  const production = moduleProductionById.get(moduleId);
  if (!production) {
    return null;
  }

  const stationInventory = world.stations.get(stationId)?.inventory ?? [];
  const inputLines = production.inputs
    .map((entry) => `  ${entry.itemId}: ${entry.amount.toFixed(0)} required / ${inventoryAmount(stationInventory, entry.itemId).toFixed(0)} available`)
    .join("\n");
  const outputLines = production.outputs
    .map((entry) => `  ${entry.itemId}: ${entry.amount.toFixed(0)}`)
    .join("\n");

  return `Cycle: ${formatDuration(production.cycleSeconds)}\nInputs:\n${inputLines || "  none"}\nOutputs:\n${outputLines || "  none"}`;
}

function formatModuleListWithConstruction(
  world: WorldState,
  stationId: string,
  installedModules: string[],
  currentProcesses: {
    lane: string;
    label: string;
    progress: number;
    timeRemainingSeconds: number;
    cycleSeconds: number;
    inputs: { itemId: string; amount: number }[];
    outputs: { itemId: string; amount: number }[];
  }[],
): string {
  const processByModule = new Map<string, { label: string; progress: number; timeRemainingSeconds: number; cycleSeconds: number; inputs: { itemId: string; amount: number }[]; outputs: { itemId: string; amount: number }[] }[]>();
  for (const process of currentProcesses) {
    const existing = processByModule.get(process.lane) ?? [];
    existing.push({ label: process.label, progress: process.progress, timeRemainingSeconds: process.timeRemainingSeconds, cycleSeconds: process.cycleSeconds, inputs: process.inputs, outputs: process.outputs });
    processByModule.set(process.lane, existing);
  }

  const renderedProcessCount = new Map<string, number>();
  const moduleHtmlParts = installedModules.map((moduleId) => {
    const processIndex = renderedProcessCount.get(moduleId) ?? 0;
    const processes = processByModule.get(moduleId) ?? [];
    const process = processes[processIndex];
    renderedProcessCount.set(moduleId, processIndex + 1);
    const moduleName = moduleNameById.get(moduleId) ?? moduleId;
    if (!process) {
      const tooltip = buildStaticModuleTooltip(world, stationId, moduleId);
      return tooltip
        ? `<div class="detail-progress-label" title="${escapeAttr(tooltip)}"><span>${moduleName}</span><span>idle</span></div>`
        : `<div class="detail-progress-label"><span>${moduleName}</span></div>`;
    }

    const inputLines = process.inputs.map((e) => `  ${e.itemId}: ${e.amount.toFixed(0)}`).join("\n");
    const outputLines = process.outputs.map((e) => `  ${e.itemId}: ${e.amount.toFixed(0)}`).join("\n");
    const tooltip = `Cycle: ${formatDuration(process.cycleSeconds)}\nInputs:\n${inputLines || "  none"}\nOutputs:\n${outputLines || "  none"}`;
    const rightLabel = `${Math.round(process.progress * 100)}% · ${formatDuration(process.timeRemainingSeconds)}`;
    return `<div class="detail-progress-label" title="${escapeAttr(tooltip)}"><span>${moduleName}</span><span>${rightLabel}</span></div>${renderProgressBar(process.progress)}`;
  });

  const activeSites = [...world.constructionSites.values()]
    .filter((site) => site.stationId === stationId && site.state !== "completed")
    .sort((left, right) => left.targetDefinitionId.localeCompare(right.targetDefinitionId));

  for (const site of activeSites) {
    const moduleId = site.blueprintId ?? site.targetDefinitionId;
    const moduleName = moduleNameById.get(moduleId) ?? moduleId;
    const progress = site.progress;
    const constructionTooltip = site.requiredItems.length > 0
      ? site.requiredItems
        .map((entry) => `${entry.itemId}: ${entry.amount.toFixed(0)} required / ${inventoryAmount(site.stationId ? (world.stations.get(site.stationId)?.inventory ?? []) : site.deliveredItems, entry.itemId).toFixed(0)} available`)
        .join("\n")
      : "No material requirements";
    moduleHtmlParts.push(`<div class="detail-progress-label" title="${escapeAttr(constructionTooltip)}"><span>${moduleName}</span><span>${Math.round(progress * 100)}% constructing</span></div>${renderProgressBar(progress)}`);
  }

  return moduleHtmlParts.length > 0 ? moduleHtmlParts.join("<br>") : "none";
}

function formatStorageClassLabel(storageClass: string): string {
  return storageClass
    .split("-")
    .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)
    .join(" ");
}

function formatStorageWithInventory(
  storageUsage: { storageClass: string; used: number; capacity: number }[],
  inventory: { itemId: string; amount: number }[],
): string {
  if (storageUsage.length === 0) {
    return inventory.length === 0 ? "none" : inventory.map((e) => `${e.itemId} ${e.amount.toFixed(0)}`).join("<br>");
  }

  const itemsByClass = new Map<string, { itemId: string; amount: number }[]>();
  for (const entry of inventory) {
    const cls = itemTransportById.get(entry.itemId) ?? "unknown";
    const list = itemsByClass.get(cls) ?? [];
    list.push(entry);
    itemsByClass.set(cls, list);
  }

  return storageUsage
    .map((entry) => {
      const percentUsed = entry.capacity > 0 ? Math.round((entry.used / entry.capacity) * 100) : 0;
      const header = `${formatStorageClassLabel(entry.storageClass)} ${percentUsed}% (${entry.used.toFixed(0)} / ${entry.capacity.toFixed(0)})`;
      const items = itemsByClass.get(entry.storageClass) ?? [];
      if (items.length === 0) {
        return `${header}<br><span style="padding-left:1em">empty</span>`;
      }
      return `${header}<br>${items.map((e) => `<span style="padding-left:1em">${e.itemId} ${e.amount.toFixed(0)}</span>`).join("<br>")}`;
    })
    .join("<br>");
}

function renderSystemOwnership(world: WorldState, systemId: string): string {
  const control = world.geopolitics?.territory.controlStates.find((state) => state.systemId === systemId);
  const zone = world.geopolitics?.territory.zones.find((entry) => entry.systemId === systemId);
  const profile = world.geopolitics?.territory.strategicProfiles.find((entry) => entry.systemId === systemId);
  const pressure = world.geopolitics?.territory.pressures.find((entry) => entry.systemId === systemId);
  const region = world.geopolitics?.economyRegions.regions.find((entry) => entry.systemIds.includes(systemId));
  const front = world.geopolitics?.territory.frontLines.find((entry) => entry.systemIds.includes(systemId));

  if (!control) {
    const claims = [...world.claims.values()].filter((claim) =>
      claim.systemId === systemId && claim.state !== "destroyed");
    return claims.length === 0 ? "Territory unknown" : `Claims ${claims.length}`;
  }

  const controllerLabel = control.controllerFactionId
    ? (world.factions.get(control.controllerFactionId)?.label ?? control.controllerFactionId)
    : "none";
  const claimantLabel = control.primaryClaimantFactionId
    ? (world.factions.get(control.primaryClaimantFactionId)?.label ?? control.primaryClaimantFactionId)
    : "none";
  const lines = [
    `Control ${control.controlKind} · Controller ${controllerLabel}`,
    `Claimant ${claimantLabel} · Zone ${zone?.kind ?? profile?.zoneKind ?? "unknown"}`,
    `Pressure ${Math.round((pressure?.pressureScore ?? profile?.territorialPressure ?? 0) * 100)}% · Security ${Math.round((pressure?.securityScore ?? profile?.securityRating ?? 0) * 100)}%`,
  ];
  if (front) {
    lines.push(`Front ${front.id} · ${front.factionIds.join(" vs ")}`);
  }
  if (region) {
    lines.push(`Region ${region.label} · ${region.kind}`);
  }
  return lines.join("<br>");
}

function titleCaseLabel(value: string | null | undefined): string {
  if (!value) {
    return "Unknown";
  }

  return value
    .replace(/([a-z])([A-Z])/g, "$1 $2")
    .replace(/[-_]+/g, " ")
    .replace(/\s+/g, " ")
    .trim()
    .replace(/\b\w/g, (part) => part.toUpperCase());
}

function describeSystemSubtitle(world: WorldState, systemId: string): string {
  const control = world.geopolitics?.territory.controlStates.find((state) => state.systemId === systemId);
  const zone = world.geopolitics?.territory.zones.find((entry) => entry.systemId === systemId);
  const profile = world.geopolitics?.territory.strategicProfiles.find((entry) => entry.systemId === systemId);
  const region = world.geopolitics?.economyRegions.regions.find((entry) => entry.systemIds.includes(systemId));

  if (region?.label) {
    return region.label;
  }

  if (zone?.reason) {
    return titleCaseLabel(zone.reason);
  }

  if (zone?.kind) {
    return titleCaseLabel(zone.kind);
  }

  if (profile?.zoneKind) {
    return titleCaseLabel(profile.zoneKind);
  }

  if (control?.isContested) {
    return "Contested";
  }

  if (control) {
    return titleCaseLabel(control.controlKind);
  }

  const claims = [...world.claims.values()].filter((claim) =>
    claim.systemId === systemId && claim.state !== "destroyed");
  return claims.length === 0 ? "Deep Space" : `Claims ${claims.length}`;
}

export function buildDetailPanelState(params: DetailPanelParams) {
  const {
    world,
    selectedItems,
    povLevel,
    cameraMode,
    cameraTargetShipId,
    worldLabel,
    describeSelectionParent,
  } = params;

  if (selectedItems.length === 0) {
    return {
      title: worldLabel,
      bodyHtml: `
        Zoom ${povLevel}<br>
        Systems ${world.systems.size}<br>
        Celestials ${world.celestials.size}<br>
        Stations ${world.stations.size}<br>
        Claims ${world.claims.size}<br>
        Construction ${world.constructionSites.size}<br>
        Ships ${world.ships.size}<br>
        Recent events ${world.recentEvents.length}
      `,
    };
  }

  if (selectedItems.length > 1) {
    const group = getSelectionGroup(selectedItems[0]);
    return {
      title: `${selectedItems.length} selected`,
      bodyHtml: `
        Type ${group}<br>
        ${selectedItems.slice(0, 8).map((item) => describeSelectable(world, item)).join("<br>")}
      `,
    };
  }

  const selected = selectedItems[0];
  if (selected.kind === "ship") {
    const ship = world.ships.get(selected.id);
    if (!ship) {
      return { title: "Missing ship", bodyHtml: "" };
    }
    const parent = describeSelectionParent(selected);
    const cargoUsed = ship.inventory.reduce((sum, e) => sum + e.amount, 0);
    const shipState = describeShipState(world, ship);
    const shipBehavior = describeShipBehavior(ship);
    const shipOrder = describeShipOrder(ship);
    const shipAction = describeShipCurrentAction(ship);
    const currentStep = ship.activePlan?.steps[ship.activePlan.currentStepIndex];
    const orderQueue = ship.orderQueue.length > 0
      ? ship.orderQueue.slice(0, 4).map((order) => `${getShipOrderLabel(order.kind)} [${order.status}]`).join("<br>")
      : "none";
    const subTaskList = ship.activeSubTasks.length > 0
      ? ship.activeSubTasks.slice(0, 4).map((subTask) => `${subTask.summary || subTask.kind} · ${subTask.status}`).join("<br>")
      : "none";
    const playerFaction = usePlayerFactionStore(viewerPinia).playerFaction;
    const playerAssignment = playerFaction?.assignments.find((assignment) => assignment.assetKind === "ship" && assignment.assetId === ship.id);
    const playerDirective = playerAssignment?.directiveId
      ? playerFaction?.directives.find((directive) => directive.id === playerAssignment.directiveId)
      : undefined;
    return {
      title: ship.name,
      bodyHtml: `
        <p>Parent ${parent}</p>
        <p>Behavior ${shipBehavior}</p>
        <p>Command ${ship.controlSourceKind}${ship.controlSourceId ? `<br>ID ${ship.controlSourceId}` : ""}${ship.controlReason ? `<br>${ship.controlReason}` : ""}</p>
        <p>Assignment ${ship.assignment?.kind ?? "unassigned"}${ship.assignment?.campaignId ? `<br>Campaign ${ship.assignment.campaignId}` : ""}</p>
        ${playerAssignment ? `<p>Player ${playerAssignment.role}${playerDirective ? `<br>Directive ${playerDirective.label}` : ""}${playerAssignment.fleetId ? `<br>Fleet ${playerAssignment.fleetId}` : ""}${playerAssignment.taskForceId ? `<br>Task Force ${playerAssignment.taskForceId}` : ""}${playerAssignment.frontId ? `<br>Front ${playerAssignment.frontId}` : ""}</p>` : ""}
        <p>State ${shipState}</p>
        <p>Order ${shipOrder}</p>
        <p>Queue ${orderQueue}</p>
        <p>Plan ${ship.activePlan ? `${ship.activePlan.kind} · ${ship.activePlan.status}` : "none"}${currentStep ? `<br>Step ${currentStep.kind} · ${currentStep.status}` : ""}</p>
        <p>Subtasks ${subTaskList}</p>
        ${ship.lastReplanReason ? `<p>Last replan ${ship.lastReplanReason}</p>` : ""}
        ${ship.lastAccessFailureReason ? `<p>Access ${ship.lastAccessFailureReason}</p>` : ""}
        ${shipAction ? `
          <div class="detail-progress">
            <div class="detail-progress-label">
              <span>${shipAction.label}</span>
              <span>${Math.round(shipAction.progress * 100)}%</span>
            </div>
            <div class="detail-progress-track">
              <div class="detail-progress-fill" style="width: ${(shipAction.progress * 100).toFixed(1)}%"></div>
            </div>
          </div>
        ` : ""}
        <p>Cargo ${cargoUsed.toFixed(0)} / ${ship.cargoCapacity.toFixed(0)}</p>
        <p>Inventory ${formatInventory(ship.inventory)}</p>
        <p>Speed ${formatShipSpeed(ship)}</p>
        <p>Camera ${cameraMode === "follow" && cameraTargetShipId === ship.id ? "camera-follow" : "tactical"}<br>Press C to toggle follow</p>
      `,
    };
  }

  if (selected.kind === "station") {
    const station = world.stations.get(selected.id);
    if (!station) {
      return { title: "Missing station", bodyHtml: "" };
    }
    const parent = describeSelectionParent(selected);
    const moduleList = formatModuleListWithConstruction(world, station.id, station.installedModules, station.currentProcesses);
    const dockedShipLabels = station.dockedShipIds.length > 0
      ? station.dockedShipIds.map((shipId) => world.ships.get(shipId)?.name ?? shipId).join("<br>")
      : "none";
    const stationStorage = formatStorageWithInventory(station.storageUsage, station.inventory);
    const playerFaction = usePlayerFactionStore(viewerPinia).playerFaction;
    const playerAssignment = playerFaction?.assignments.find((assignment) => assignment.assetKind === "station" && assignment.assetId === station.id);
    const playerDirective = playerAssignment?.directiveId
      ? playerFaction?.directives.find((directive) => directive.id === playerAssignment.directiveId)
      : undefined;
    return {
      title: station.label,
      bodyHtml: `
        <p>${station.category} · ${station.systemId}</p>
        <p>Parent ${parent}</p>
        ${playerAssignment ? `<p>Player ${playerAssignment.role}${playerDirective ? `<br>Directive ${playerDirective.label}` : ""}${playerAssignment.stationGroupId ? `<br>Group ${playerAssignment.stationGroupId}` : ""}${playerAssignment.economicRegionId ? `<br>Region ${playerAssignment.economicRegionId}` : ""}</p>` : ""}
        <p>Docked ${station.dockedShips} / ${station.dockingPads}
        <br>
        ${dockedShipLabels}</p>
        <p>Modules ${moduleList}</p>
        <p>Storage ${stationStorage}</p>
      `,
    };
  }

  if (selected.kind === "node") {
    const node = world.nodes.get(selected.id);
    if (!node) {
      return { title: "Missing node", bodyHtml: "" };
    }
    const parent = describeSelectionParent(selected);
    const nodeLevel = node.maxOre > 0
      ? Math.max(0, Math.min(node.oreRemaining / node.maxOre, 1))
      : 0;
    return {
      title: `Node ${node.id}`,
      bodyHtml: `
        <p>${node.systemId}</p>
        <p>Parent ${parent}</p>
        <p>Source ${node.sourceKind}<br>Resource ${node.itemId}</p>
        <div class="detail-progress">
          <div class="detail-progress-label">
            <span>Level</span>
            <span>${Math.round(nodeLevel * 100)}%</span>
          </div>
          <div class="detail-progress-track">
            <div class="detail-progress-fill" style="width: ${(nodeLevel * 100).toFixed(1)}%"></div>
          </div>
        </div>
        <p>Stock ${node.oreRemaining.toFixed(0)} / ${node.maxOre.toFixed(0)}</p>
      `,
    };
  }

  if (selected.kind === "celestial") {
    const celestial = world.celestials.get(selected.id);
    if (!celestial) {
      return { title: "Missing celestial", bodyHtml: "" };
    }
    return {
      title: `${celestial.kind} celestial`,
      bodyHtml: `
        <p>${celestial.systemId}</p>
        <p>Parent ${celestial.parentNodeId ?? "none"}<br>Orbit ref ${celestial.orbitReferenceId ?? "none"}</p>
        <p>Occupying structure ${celestial.occupyingStructureId ?? "none"}</p>
        <p>Local space radius ${celestial.localSpaceRadius.toFixed(0)} km</p>
      `,
    };
  }

  if (selected.kind === "claim") {
    const claim = world.claims.get(selected.id);
    if (!claim) {
      return { title: "Missing claim", bodyHtml: "" };
    }
    return {
      title: `Claim ${claim.id}`,
      bodyHtml: `
        <p>${claim.systemId}</p>
        <p>Celestial ${claim.celestialId}</p>
        <p>State ${claim.state}<br>Health ${claim.health.toFixed(0)}</p>
        <p>Activates ${new Date(claim.activatesAtUtc).toLocaleTimeString()}</p>
      `,
    };
  }

  if (selected.kind === "construction-site") {
    const site = world.constructionSites.get(selected.id);
    if (!site) {
      return { title: "Missing construction", bodyHtml: "" };
    }
    const orderCount = [...world.marketOrders.values()].filter((order) => order.constructionSiteId === site.id).length;
    return {
      title: `Construction ${site.id}`,
      bodyHtml: `
        <p>${site.systemId}</p>
        <p>Celestial ${site.celestialId}</p>
        <p>${site.targetKind} ${site.targetDefinitionId}</p>
        <p>State ${site.state}<br>Progress ${(site.progress * 100).toFixed(0)}%</p>
        <p>Orders ${orderCount}<br>Assigned constructors ${site.assignedConstructorShipIds.length}</p>
      `,
    };
  }

  if (selected.kind === "planet") {
    const system = world.systems.get(selected.systemId);
    const planet = system?.planets[selected.planetIndex];
    if (!system || !planet) {
      return { title: "Missing planet", bodyHtml: "" };
    }
    const parent = describeSelectionParent(selected);
    return {
      title: planet.label,
      bodyHtml: `
        <p>${system.label}</p>
        <p>Parent ${parent}</p>
        <p>${planet.planetType} · ${planet.shape} · Moons ${planet.moons.length}</p>
        <p>Orbit ${formatSystemDistance(planet.orbitRadius)}<br>Speed ${planet.orbitSpeed.toFixed(3)}<br>Ecc ${planet.orbitEccentricity.toFixed(3)}<br>Inc ${planet.orbitInclination.toFixed(1)}°</p>
        <p>Phase ${planet.orbitPhaseAtEpoch.toFixed(1)}°</p>
      `,
    };
  }

  if (selected.kind === "moon") {
    const system = world.systems.get(selected.systemId);
    const planet = system?.planets[selected.planetIndex];
    const moon = planet?.moons[selected.moonIndex];
    if (moon) {
      return {
        title: moon.label,
        bodyHtml: `
          <p>${system?.label ?? selected.systemId} / ${planet?.label ?? `planet ${selected.planetIndex + 1}`}</p>
          <p>Orbit ${formatSystemDistance(moon.orbitRadius)}<br>Inc ${moon.orbitInclination.toFixed(1)}°</p>
        `,
      };
    }
    return { title: "Moon", bodyHtml: "" };
  }

  const system = world.systems.get(selected.id);
  if (!system) {
    return {
      title: "Unknown selection",
      bodyHtml: "",
    };
  }

  return {
    title: system.label,
    bodyHtml: `
      <p>Parent galaxy</p>
      ${renderSystemDetails(world, system, false, cameraMode, cameraTargetShipId)}
    `,
  };
}

export function buildSystemPanelState(params: SystemPanelParams) {
  const {
    world,
    activeSystemId,
  } = params;

  const activeSystem = activeSystemId ? world.systems.get(activeSystemId) : undefined;

  if (!activeSystem) {
    return {
      hidden: true,
      title: "Deep Space",
      bodyHtml: "",
    };
  }

  return {
    hidden: false,
    title: activeSystem.label,
    bodyHtml: describeSystemSubtitle(world, activeSystem.id),
  };
}

export function describeSelectionParent(
  world: WorldState | undefined,
  selection: Selectable,
  stationVisuals: Map<string, StructureVisual>,
  nodeVisuals: Map<string, NodeVisual>,
) {
  if (!world) {
    return "unknown";
  }

  if (selection.kind === "system") {
    return "galaxy";
  }
  if (selection.kind === "planet") {
    const system = world.systems.get(selection.systemId);
    return system ? `${system.label} star` : selection.systemId;
  }
  if (selection.kind === "ship") {
    const ship = world.ships.get(selection.id);
    if (!ship) {
      return "unknown";
    }
    const system = world.systems.get(ship.systemId);
    return system ? `${system.label} system` : ship.systemId;
  }
  if (selection.kind === "station") {
    const station = world.stations.get(selection.id);
    if (!station) {
      return "unknown";
    }

    return station.celestialId
      ? describeCelestialPathWithinSystem(world, station.systemId, station.celestialId) ?? `${station.systemId} network`
      : "unknown";
  }
  if (selection.kind === "node") {
    const node = world.nodes.get(selection.id);
    const visual = node ? nodeVisuals.get(selection.id) : undefined;
    return describeOrbitalParent(world, node?.systemId, visual?.anchor);
  }
  if (selection.kind === "celestial") {
    const celestial = world.celestials.get(selection.id);
    return celestial?.parentNodeId ?? `${celestial?.systemId ?? "unknown"} network`;
  }
  if (selection.kind === "claim") {
    return world.claims.get(selection.id)?.celestialId ?? "unknown";
  }
  if (selection.kind === "construction-site") {
    return world.constructionSites.get(selection.id)?.celestialId ?? "unknown";
  }

  return "unknown";
}
