import type { CelestialSnapshot, ShipSnapshot, SystemSnapshot } from "./contracts";
import type {
  CameraMode,
  OrbitalAnchor,
  Selectable,
  SelectionGroup,
  WorldState,
} from "./viewerTypes";
import { formatGalaxyDistance } from "./viewerMath";
import { getShipBehaviorLabel, getShipOrderLabel } from "./shipAutomationPresentation";

export function describeSelectable(world: WorldState | undefined, item: Selectable): string {
  if (!world) {
    return item.kind;
  }
  if (item.kind === "ship") {
    return world.ships.get(item.id)?.name ?? item.id;
  }
  if (item.kind === "station") {
    return world.stations.get(item.id)?.label ?? item.id;
  }
  if (item.kind === "node") {
    return item.id;
  }
  if (item.kind === "celestial") {
    return `${world.celestials.get(item.id)?.kind ?? "celestial"} ${item.id}`;
  }
  if (item.kind === "claim") {
    return `claim ${item.id}`;
  }
  if (item.kind === "construction-site") {
    return `construction ${item.id}`;
  }
  if (item.kind === "planet") {
    return world.systems.get(item.systemId)?.planets[item.planetIndex]?.label ?? `${item.systemId}:${item.planetIndex}`;
  }
  if (item.kind === "moon") {
    const planet = world.systems.get(item.systemId)?.planets[item.planetIndex];
    return planet?.moons[item.moonIndex]?.label ?? `moon ${item.moonIndex + 1}`;
  }
  return world.systems.get(item.id)?.label ?? item.id;
}

export function describeHoverLabel(world: WorldState | undefined, item: Selectable): string | undefined {
  if (!world) {
    return undefined;
  }

  if (item.kind === "ship") {
    const ship = world.ships.get(item.id);
    if (!ship) {
      return item.id;
    }

    const lines = [
      ship.name,
      `Behavior ${describeShipBehavior(ship)}`,
      `State ${describeShipState(world, ship)}`,
      `Order ${describeShipOrder(ship)}`,
    ];
    return lines.join("\n");
  }

  if (item.kind === "station") {
    return world.stations.get(item.id)?.label ?? item.id;
  }

  if (item.kind === "system") {
    const system = world.systems.get(item.id);
    if (!system) {
      return item.id;
    }
    const starLabel = system.stars.length > 1 ? `${system.stars.length}× ${system.stars[0]?.kind}` : (system.stars[0]?.kind ?? "unknown");
    const planetCount = system.planets.length;
    const shipCount = [...world.ships.values()].filter((s) => s.systemId === item.id).length;
    const stationCount = [...world.stations.values()].filter((s) => s.systemId === item.id).length;
    const lines = [
      system.label,
      `${starLabel} · ${planetCount} planet${planetCount !== 1 ? "s" : ""}`,
    ];
    const parts: string[] = [];
    if (shipCount > 0) {
      parts.push(`${shipCount} ship${shipCount !== 1 ? "s" : ""}`);
    }
    if (stationCount > 0) {
      parts.push(`${stationCount} station${stationCount !== 1 ? "s" : ""}`);
    }
    if (parts.length > 0) {
      lines.push(parts.join(" · "));
    }
    return lines.join("\n");
  }

  if (item.kind === "planet") {
    const system = world.systems.get(item.systemId);
    const planet = system?.planets[item.planetIndex];
    return planet ? `${system?.label ?? item.systemId} / ${planet.label}` : `${item.systemId} / planet ${item.planetIndex + 1}`;
  }

  if (item.kind === "moon") {
    const system = world.systems.get(item.systemId);
    const planet = system?.planets[item.planetIndex];
    const moon = planet?.moons[item.moonIndex];
    if (moon) {
      return `${system?.label ?? item.systemId} / ${planet?.label ?? `planet ${item.planetIndex + 1}`} / ${moon.label}`;
    }
    return `${item.systemId} / planet ${item.planetIndex + 1} / moon ${item.moonIndex + 1}`;
  }

  if (item.kind === "node") {
    const node = world.nodes.get(item.id);
    if (!node) {
      return item.id;
    }

    const anchorPath = node.celestialId
      ? describeCelestialPathWithinSystem(world, node.systemId, node.celestialId)
      : undefined;
    return anchorPath ? `${anchorPath} / ${node.itemId}` : `${node.systemId} / ${node.itemId}`;
  }

  if (item.kind === "celestial") {
    const celestial = world.celestials.get(item.id);
    if (!celestial) {
      return item.id;
    }

    if (celestial.kind === "star") {
      const system = world.systems.get(celestial.systemId);
      return system ? `${system.label} star` : `${celestial.systemId} star`;
    }

    return describeCelestialPathWithinSystem(world, celestial.systemId, celestial.id) ?? `${celestial.systemId} / ${celestial.kind}`;
  }

  if (item.kind === "claim") {
    const claim = world.claims.get(item.id);
    const anchorPath = claim?.celestialId
      ? describeCelestialPathWithinSystem(world, claim.systemId, claim.celestialId)
      : undefined;
    return anchorPath ? `${anchorPath} claim` : `Claim ${item.id}`;
  }

  if (item.kind === "construction-site") {
    const site = world.constructionSites.get(item.id);
    const anchorPath = site?.celestialId
      ? describeCelestialPathWithinSystem(world, site.systemId, site.celestialId)
      : undefined;
    const siteLabel = site ? (site.blueprintId ?? site.targetDefinitionId) : item.id;
    return anchorPath ? `${anchorPath} / ${siteLabel}` : `Construction ${siteLabel}`;
  }

  return describeSelectable(world, item);
}

export function getSelectionGroup(item: Selectable): SelectionGroup {
  if (item.kind === "ship") {
    return "ships";
  }
  if (
    item.kind === "station"
    || item.kind === "node"
    || item.kind === "claim"
    || item.kind === "construction-site"
  ) {
    return "structures";
  }
  return "celestials";
}

export function resolveSelectableSystemId(world: WorldState | undefined, selection: Selectable): string | undefined {
  if (!world) {
    return undefined;
  }

  if (selection.kind === "ship") {
    return world.ships.get(selection.id)?.systemId;
  }
  if (selection.kind === "station") {
    return world.stations.get(selection.id)?.systemId;
  }
  if (selection.kind === "node") {
    return world.nodes.get(selection.id)?.systemId;
  }
  if (selection.kind === "celestial") {
    return world.celestials.get(selection.id)?.systemId;
  }
  if (selection.kind === "claim") {
    return world.claims.get(selection.id)?.systemId;
  }
  if (selection.kind === "construction-site") {
    return world.constructionSites.get(selection.id)?.systemId;
  }
  if (selection.kind === "planet") {
    return selection.systemId;
  }
  if (selection.kind === "moon") {
    return selection.systemId;
  }
  return selection.id;
}

export function resolveFocusedCelestialId(world: WorldState | undefined, selectedItems: Selectable[]): string | undefined {
  if (!world || selectedItems.length !== 1) {
    return undefined;
  }

  const selected = selectedItems[0];
  if (selected.kind === "celestial") {
    return selected.id;
  }
  if (selected.kind === "ship") {
    return world.ships.get(selected.id)?.spatialState.currentCelestialId ?? world.ships.get(selected.id)?.celestialId ?? undefined;
  }
  if (selected.kind === "station") {
    return world.stations.get(selected.id)?.celestialId ?? undefined;
  }
  if (selected.kind === "claim") {
    return world.claims.get(selected.id)?.celestialId ?? undefined;
  }
  if (selected.kind === "construction-site") {
    return world.constructionSites.get(selected.id)?.celestialId ?? undefined;
  }
  return undefined;
}

export function describeOrbitalParent(world: WorldState | undefined, systemId?: string, anchor?: OrbitalAnchor): string {
  if (!world || !systemId) {
    return "unknown";
  }

  const system = world.systems.get(systemId);
  if (!system) {
    return systemId;
  }

  if (!anchor || anchor.kind === "star") {
    return `${system.label} star`;
  }

  const planet = system.planets[anchor.planetIndex];
  if (!planet) {
    return `${system.label} star`;
  }

  if (anchor.kind === "planet") {
    return planet.label;
  }

  return `${planet.label} moon ${anchor.moonIndex + 1}`;
}

export function renderSystemDetails(
  world: WorldState | undefined,
  system: SystemSnapshot,
  activeContext: boolean,
  cameraMode: CameraMode,
  cameraTargetShipId?: string,
): string {
  if (!world) {
    return "";
  }

  let shipCount = 0;
  let stationCount = 0;
  let nodeCount = 0;
  let celestialCount = 0;
  let claimCount = 0;
  let constructionCount = 0;
  let moonCount = 0;

  for (const ship of world.ships.values()) {
    if (ship.systemId === system.id) {
      shipCount += 1;
    }
  }
  for (const station of world.stations.values()) {
    if (station.systemId === system.id) {
      stationCount += 1;
    }
  }
  for (const node of world.nodes.values()) {
    if (node.systemId === system.id) {
      nodeCount += 1;
    }
  }
  for (const celestial of world.celestials.values()) {
    if (celestial.systemId === system.id) {
      celestialCount += 1;
    }
  }
  for (const claim of world.claims.values()) {
    if (claim.systemId === system.id) {
      claimCount += 1;
    }
  }
  for (const site of world.constructionSites.values()) {
    if (site.systemId === system.id) {
      constructionCount += 1;
    }
  }
  for (const planet of system.planets) {
    moonCount += planet.moons.length;
  }

  const followText = activeContext && cameraMode === "follow" && cameraTargetShipId
    ? `<p>Camera locked to ${world.ships.get(cameraTargetShipId)?.name ?? cameraTargetShipId}</p>`
    : "";

  return `
    <p>${system.id}${activeContext ? " · active system" : ""}</p>
    <p>${system.stars[0]?.kind ?? "unknown"} · ${system.stars.length} star${system.stars.length > 1 ? "s" : ""}</p>
    <p>Planets ${system.planets.length}<br>Moons ${moonCount}<br>Ships ${shipCount}<br>Stations ${stationCount}</p>
    <p>Celestials ${celestialCount}<br>Resource nodes ${nodeCount}</p>
    <p>Claims ${claimCount}<br>Construction sites ${constructionCount}</p>
    <p>Height ${formatGalaxyDistance(system.galaxyPosition.y)}</p>
    <p>${system.planets.slice(0, 8).map((planet) => `${planet.label} (${planet.planetType})`).join("<br>")}</p>
    ${followText}
  `;
}

export function describeShipState(world: WorldState | undefined, ship: ShipSnapshot): string {
  const baseState = ship.state;
  const currentSubTask = ship.activeSubTasks[0];
  if (baseState === "capacitor-starved") {
    return currentSubTask ? `${baseState} while ${titleTask(currentSubTask.kind)}` : baseState;
  }

  if (!world || (baseState !== "ftl" && baseState !== "spooling-ftl" && baseState !== "warping" && baseState !== "spooling-warp")) {
    return baseState;
  }

  const destinationNodeId = ship.spatialState.destinationNodeId ?? ship.spatialState.transit?.destinationNodeId;
  if (!destinationNodeId) {
    return baseState;
  }

  const destinationCelestial = world.celestials.get(destinationNodeId);
  if (!destinationCelestial) {
    return `${baseState} -> ${destinationNodeId}`;
  }

  if (baseState === "warping" || baseState === "spooling-warp") {
    const destinationPath = describeCelestialPathWithinSystem(world, destinationCelestial.systemId, destinationNodeId);
    return `${baseState} -> ${destinationPath ?? destinationNodeId}`;
  }

  const destinationSystem = world.systems.get(destinationCelestial.systemId);
  return `${baseState} -> ${destinationSystem?.label ?? destinationCelestial.systemId}`;
}

export function describeShipObjective(objective: string): string {
  return objective.replace(/[-_]+/g, " ");
}

export function describeShipBehavior(ship: ShipSnapshot): string {
  const parts = [getShipBehaviorLabel(ship.defaultBehavior.kind)];
  if (ship.assignment?.kind) {
    parts.push(ship.assignment.kind);
  }
  return parts.join(" · ");
}

export function describeShipOrder(ship: ShipSnapshot): string {
  const activeOrder = [...ship.orderQueue]
    .sort((left, right) => right.priority - left.priority || left.createdAtUtc.localeCompare(right.createdAtUtc))[0];
  if (activeOrder) {
    return activeOrder.label ?? getShipOrderLabel(activeOrder.kind);
  }

  if (ship.assignment?.kind) {
    return describeShipObjective(ship.assignment.kind);
  }

  if (ship.activePlan) {
    return ship.activePlan.summary || ship.activePlan.kind;
  }

  return getShipBehaviorLabel(ship.defaultBehavior.kind);
}

export function describeShipCurrentAction(ship: ShipSnapshot): { label: string; progress: number } | undefined {
  const subTask = ship.activeSubTasks[0];
  if (!subTask) {
    return undefined;
  }

  return {
    label: subTask.summary || titleTask(subTask.kind),
    progress: Math.max(0, Math.min(subTask.progress, 1)),
  };
}

function titleTask(value: string): string {
  return value.replace(/[-_]+/g, " ");
}

export function describeShipLocation(world: WorldState | undefined, ship: ShipSnapshot): { system: string; local?: string } {
  const systemId = ship.spatialState.currentSystemId || ship.systemId;
  const system = world?.systems.get(systemId);
  const systemLabel = system?.label ?? systemId;
  if (!world || !system) {
    return { system: systemLabel };
  }

  if (ship.dockedStationId) {
    const station = world.stations.get(ship.dockedStationId);
    if (station) {
      const anchorPath = station.celestialId
        ? describeCelestialPathWithinSystem(world, station.systemId, station.celestialId)
        : undefined;
      return {
        system: systemLabel,
        local: anchorPath ? `${anchorPath}/${station.label}` : station.label,
      };
    }
  }

  const currentCelestialId = ship.spatialState.currentCelestialId ?? ship.celestialId;
  if (currentCelestialId) {
    const celestialPath = describeCelestialPathWithinSystem(world, systemId, currentCelestialId);
    if (celestialPath) {
      return { system: systemLabel, local: celestialPath };
    }
  }

  return { system: systemLabel };
}

export function describeActiveSpace(
  world: WorldState | undefined,
  povLevel: "local" | "system" | "galaxy",
  activeSystemId: string | undefined,
  selectedItems: Selectable[],
): string {
  if (!world || povLevel === "galaxy") {
    return "deep-space";
  }

  const activeSystem = activeSystemId ? world.systems.get(activeSystemId) : undefined;
  if (!activeSystem) {
    return "deep-space";
  }

  if (povLevel !== "local") {
    return activeSystem.label;
  }

  const celestialId = resolveFocusedCelestialId(world, selectedItems);
  if (celestialId) {
    const localPath = describeCelestialPathWithinSystem(world, activeSystem.id, celestialId);
    return localPath
      ? `${activeSystem.label} / ${localPath}`
      : activeSystem.label;
  }

  const selected = selectedItems.length === 1 ? selectedItems[0] : undefined;
  if (selected?.kind === "planet" && selected.systemId === activeSystem.id) {
    const planet = activeSystem.planets[selected.planetIndex];
    return planet
      ? `${activeSystem.label} / ${planet.label}`
      : activeSystem.label;
  }

  return activeSystem.label;
}

export function describeCelestialPathWithinSystem(world: WorldState, systemId: string, celestialId: string): string | undefined {
  const celestial = world.celestials.get(celestialId);
  const system = world.systems.get(systemId);
  if (!celestial || !system) {
    return undefined;
  }

  if (celestial.parentNodeId) {
    const parentPath = describeCelestialPathWithinSystem(world, systemId, celestial.parentNodeId);
    const segment = describeCelestialSegment(system, celestial);
    return parentPath ? `${parentPath}/${segment}` : segment;
  }

  if (celestial.kind === "star") {
    return undefined;
  }

  return describeCelestialSegment(system, celestial);
}

function describeCelestialSegment(system: SystemSnapshot, celestial: CelestialSnapshot): string {
  const moonMatch = celestial.id.match(/-planet-(\d+)-moon-(\d+)$/);
  if (moonMatch) {
    const moonIndex = Number.parseInt(moonMatch[2], 10);
    return `Moon ${moonIndex}`;
  }

  const lagrangeMatch = celestial.id.match(/-planet-\d+-(l[1-5])$/);
  if (lagrangeMatch) {
    return lagrangeMatch[1].toUpperCase();
  }

  const planetMatch = celestial.id.match(/-planet-(\d+)$/);
  if (planetMatch) {
    const planetIndex = Number.parseInt(planetMatch[1], 10) - 1;
    return system.planets[planetIndex]?.label ?? `Planet ${planetMatch[1]}`;
  }

  return celestial.orbitReferenceId ?? celestial.kind;
}
