import { useEffect, useMemo, useState, type CSSProperties } from "react";
import { loadGalaxyData } from "../../r3f/shared/galaxyData";
import { getSystemPoiPosition } from "../../r3f/shared/poiOrbit";
import type { GalaxySystem, SystemPointOfInterest, Vec3 } from "../../r3f/shared/types";
import { localEntityPosition, MOVEMENT_SYSTEM_SCALE, MovementScene } from "../../r3f/movement/MovementScene";
import type { LocalEntity, LocalWaypoint } from "../../r3f/movement/movementState";
import type { GameSliceSession, SliceTarget, SliceTargetKind } from "../types";
import { SLICE_BELT, SLICE_BELT_POSITION, SLICE_POI_NAMES, SLICE_STATION, SLICE_STATION_POSITION, SLICE_TRAVEL_SYSTEM_IDS } from "../sliceWorld";
import { metricLabel, sliceButton, slicePanel, slicePrimaryButton } from "./sliceStyles";

type ContextAction = {
  label: string;
  run: () => void;
  disabled?: boolean;
};

type ContextMenu = {
  x: number;
  y: number;
  title: string;
  subtitle: string;
  actions: ContextAction[];
};

const SYSTEM_NAMES: Record<string, string> = { sol: "Sol", amarr: "Amarr", heinoo: "Hek", rens: "Rens", dodixie: "Dodixie" };

const menuButtonStyle: CSSProperties = {
  ...sliceButton,
  width: "100%",
  justifyContent: "flex-start",
  border: "0",
  borderRadius: 0,
  background: "transparent",
};

function fallbackPosition(poiId: string | null): Vec3 {
  if (poiId === SLICE_BELT.poiId) return SLICE_BELT_POSITION;
  if (poiId === SLICE_STATION.poiId) return SLICE_STATION_POSITION;
  return [0, 0, 0];
}

function lerpVec3(from: Vec3, to: Vec3, progress: number): Vec3 {
  return [
    from[0] + (to[0] - from[0]) * progress,
    from[1] + (to[1] - from[1]) * progress,
    from[2] + (to[2] - from[2]) * progress,
  ];
}

function poiPosition(system: GalaxySystem, poiId: string): Vec3 {
  return getSystemPoiPosition({
    systemId: system.id,
    planets: system.planets,
    pointsOfInterest: system.pointsOfInterest,
    poiId,
    scale: MOVEMENT_SYSTEM_SCALE,
    expanded: true,
  });
}

function targetKind(poi: SystemPointOfInterest): SliceTargetKind {
  if (poi.type === "station") return "station";
  if (poi.type === "asteroid_belt") return "asteroid_belt";
  return "manual";
}

function targetForPoi(systemId: string, poi: SystemPointOfInterest, position: Vec3): SliceTarget {
  return {
    id: poi.id,
    name: poi.name,
    kind: targetKind(poi),
    systemId,
    poiId: poi.id,
    position,
  };
}

function ambientTraffic(systemId: string, elapsed: number): LocalEntity[] {
  return Array.from({ length: 4 }, (_, index) => {
    const hostile = index === 2;
    const seed = index * 1.9 + systemId.length * 0.37;
    const radius = 135 + index * 34;
    return {
      id: `${systemId}-${hostile ? "hostile" : "traffic"}-${index}`,
      name: hostile ? "Guristas Scout" : ["Survey Skiff", "Customs Cutter", "Ore Hauler", "Patrol Wing"][index],
      type: hostile ? "hostile" : "friendly",
      x: 400 + Math.cos(elapsed * (0.24 + index * 0.04) + seed) * radius,
      y: 300 + Math.sin(elapsed * (0.2 + index * 0.03) + seed) * (radius * 0.62),
      distance: Math.round(radius / 6),
    };
  });
}

export function SliceFlightStage({
  session,
  operationProgress,
  onPoiTarget,
  onSystemPoiTarget,
  onSelectTarget,
  onManualTarget,
  onApproachTarget,
  onDockAtTarget,
  onMineTarget,
}: {
  session: GameSliceSession;
  operationProgress: number;
  onPoiTarget: Parameters<typeof MovementScene>[0]["onPoiPick"];
  onSystemPoiTarget: (systemId: string, poi: SystemPointOfInterest, position: Vec3) => void;
  onSelectTarget: (target: SliceTarget) => void;
  onManualTarget: Parameters<typeof MovementScene>[0]["onWaypointPick"];
  onApproachTarget: (target: SliceTarget) => void;
  onDockAtTarget: (target: SliceTarget) => void;
  onMineTarget: (target: SliceTarget) => void;
}) {
  const [systems, setSystems] = useState<GalaxySystem[]>([]);
  const [elapsed, setElapsed] = useState(0);
  const [contextMenu, setContextMenu] = useState<ContextMenu | null>(null);

  useEffect(() => {
    loadGalaxyData().then(({ systems }) => setSystems(systems));
  }, []);

  useEffect(() => {
    const started = performance.now();
    const id = window.setInterval(() => setElapsed((performance.now() - started) / 1000), 120);
    return () => window.clearInterval(id);
  }, []);

  const currentSystem = useMemo(() => systems.find((system) => system.id === session.currentSystemId) ?? systems.find((system) => system.id === "sol") ?? null, [session.currentSystemId, systems]);
  const travelSystems = useMemo(() => SLICE_TRAVEL_SYSTEM_IDS.map((id) => systems.find((system) => system.id === id)).filter(Boolean) as GalaxySystem[], [systems]);

  const currentPoiPosition = useMemo(() => {
    if (!currentSystem || !session.currentPoiId) return fallbackPosition(session.currentPoiId);
    return poiPosition(currentSystem, session.currentPoiId);
  }, [currentSystem, session.currentPoiId]);

  const shipPosition = useMemo(() => {
    if (session.activeOperation?.kind === "travel") {
      return lerpVec3(session.activeOperation.fromPosition, session.activeOperation.targetPosition, operationProgress);
    }
    return session.shipPosition ?? currentPoiPosition;
  }, [currentPoiPosition, operationProgress, session.activeOperation, session.shipPosition]);

  const localEntities = useMemo(() => ambientTraffic(session.currentSystemId, elapsed), [elapsed, session.currentSystemId]);

  const waypoint: LocalWaypoint[] = useMemo(() => {
    if (session.activeOperation?.kind === "travel") {
      const target = session.activeOperation.target;
      return [{
        id: target.id,
        name: target.name,
        type: target.poiId ? "poi" : "manual",
        systemId: target.systemId,
        poiId: target.poiId,
        position: target.position,
        arrived: false,
      }];
    }
    if (session.selectedTarget) {
      return [{
        id: session.selectedTarget.id,
        name: session.selectedTarget.name,
        type: session.selectedTarget.poiId ? "poi" : "manual",
        systemId: session.selectedTarget.systemId,
        poiId: session.selectedTarget.poiId,
        position: session.selectedTarget.position,
        arrived: session.selectedTarget.poiId === session.currentPoiId,
      }];
    }
    if (session.currentPoiId) {
      return [{ id: session.currentPoiId, name: SLICE_POI_NAMES[session.currentPoiId] ?? session.currentPoiId, type: "poi", systemId: session.currentSystemId, poiId: session.currentPoiId, position: currentPoiPosition, arrived: true }];
    }
    return [];
  }, [currentPoiPosition, session.activeOperation, session.currentPoiId, session.currentSystemId, session.selectedTarget]);

  const currentPoiName = useMemo(() => {
    if (session.selectedTarget?.poiId === session.currentPoiId) return session.selectedTarget.name;
    return currentSystem?.pointsOfInterest.find((poi) => poi.id === session.currentPoiId)?.name ?? SLICE_POI_NAMES[session.currentPoiId ?? ""] ?? "open space";
  }, [currentSystem, session.currentPoiId, session.selectedTarget]);

  const status = session.activeOperation?.kind === "travel"
    ? `Approaching ${session.activeOperation.target.name}`
    : session.selectedTarget
      ? `Selected ${session.selectedTarget.name}`
      : `Holding at ${currentPoiName}`;

  const openTargetMenu = (x: number, y: number, target: SliceTarget, subtitle: string) => {
    const atTarget = target.poiId && session.currentPoiId === target.poiId;
    const actions: ContextAction[] = [
      { label: "Select", run: () => onSelectTarget(target) },
      { label: "Approach", run: () => onApproachTarget(target), disabled: Boolean(session.dockedStationPoiId || session.activeOperation || atTarget) },
    ];
    if (target.kind === "station") actions.push({ label: "Dock", run: () => onDockAtTarget(target), disabled: !atTarget || Boolean(session.activeOperation || session.dockedStationPoiId) });
    if (target.kind === "asteroid_belt") actions.push({ label: "Mine", run: () => onMineTarget(target), disabled: !atTarget || Boolean(session.activeOperation || session.dockedStationPoiId) });
    if (target.kind === "hostile") actions.push({ label: "Target", run: () => onManualTarget({ id: target.id, name: target.name, type: "entity", position: target.position }) });
    setContextMenu({ x, y, title: target.name, subtitle, actions });
  };

  const selectPoi = (system: GalaxySystem, poi: SystemPointOfInterest) => {
    const position = poiPosition(system, poi.id);
    if (system.id === session.currentSystemId) onPoiTarget(poi, position);
    else onSystemPoiTarget(system.id, poi, position);
  };

  const openPoiMenu = (x: number, y: number, system: GalaxySystem, poi: SystemPointOfInterest) => {
    const position = poiPosition(system, poi.id);
    openTargetMenu(x, y, targetForPoi(system.id, poi, position), `${SYSTEM_NAMES[system.id] ?? system.name} ${poi.type.replace(/_/g, " ")}`);
  };

  const selectEntity = (entity: LocalEntity) => {
    const position = localEntityPosition(entity);
    onManualTarget({ id: entity.id, name: entity.name, type: "entity", position });
  };

  const openEntityMenu = (x: number, y: number, entity: LocalEntity) => {
    const position = localEntityPosition(entity);
    openTargetMenu(x, y, {
      id: entity.id,
      name: entity.name,
      kind: entity.type === "hostile" ? "hostile" : "manual",
      systemId: session.currentSystemId,
      position,
    }, entity.type === "hostile" ? "hostile contact" : "local traffic");
  };

  return (
    <section
      className="slice-loop-panel"
      onContextMenu={(event) => event.preventDefault()}
      onClick={() => setContextMenu(null)}
      style={{ ...slicePanel, position: "relative", height: "100%", minHeight: 0, overflow: "hidden" }}
    >
      <MovementScene
        currentSystemId={session.currentSystemId}
        currentSystem={currentSystem}
        localEntities={localEntities}
        localWaypoints={waypoint}
        shipPosition={shipPosition}
        onFrame={() => {}}
        onWaypointPick={onManualTarget}
        onPoiPick={onPoiTarget}
        onPoiContext={(poi, position, event) => {
          if (!currentSystem) return;
          openTargetMenu(event.nativeEvent.clientX, event.nativeEvent.clientY, targetForPoi(currentSystem.id, poi, position), poi.type.replace(/_/g, " "));
        }}
        onEntityPick={selectEntity}
        onEntityContext={(entity, _position, event) => openEntityMenu(event.nativeEvent.clientX, event.nativeEvent.clientY, entity)}
      />

      <div style={{ position: "absolute", left: 14, top: 14, right: 14, zIndex: 1, display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap", padding: "9px 10px", border: "1px solid rgba(148,163,184,0.22)", borderRadius: 8, background: "rgba(8,12,20,0.78)" }}>
        <span style={metricLabel}>Flight</span>
        <strong style={{ color: "#f0a030" }}>{status}</strong>
        {session.activeOperation?.kind === "travel" && <span style={{ marginLeft: "auto", color: "#22d3ee", fontFamily: "var(--font-mono)", fontSize: 11 }}>{Math.round(operationProgress * 100)}%</span>}
      </div>

      <div style={{ position: "absolute", left: 14, bottom: 14, zIndex: 1, width: "min(280px, calc(50% - 22px))", padding: 10, border: "1px solid rgba(148,163,184,0.22)", borderRadius: 8, background: "rgba(8,12,20,0.82)", display: "grid", gap: 8 }}>
        <div style={metricLabel}>Jump Network</div>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(5, minmax(0, 1fr))", gap: 6 }}>
          {travelSystems.map((system) => {
            const primaryPoi = system.pointsOfInterest.find((poi) => poi.type === "station") ?? system.pointsOfInterest[0];
            const active = system.id === session.currentSystemId;
            return (
              <button
                key={system.id}
                style={{ ...sliceButton, minWidth: 0, padding: "7px 4px", border: active ? "1px solid rgba(34,197,94,0.62)" : sliceButton.border, color: active ? "#22c55e" : sliceButton.color }}
                disabled={!primaryPoi}
                title={primaryPoi ? `Set route to ${primaryPoi.name}` : undefined}
                onClick={(event) => {
                  event.stopPropagation();
                  if (primaryPoi) selectPoi(system, primaryPoi);
                }}
                onContextMenu={(event) => {
                  event.preventDefault();
                  event.stopPropagation();
                  if (primaryPoi) openPoiMenu(event.clientX, event.clientY, system, primaryPoi);
                }}
              >
                {SYSTEM_NAMES[system.id] ?? system.name}
              </button>
            );
          })}
        </div>
      </div>

      <div style={{ position: "absolute", right: 14, bottom: 14, zIndex: 1, width: "min(300px, calc(50% - 22px))", maxHeight: "min(58%, 380px)", padding: 10, border: "1px solid rgba(148,163,184,0.22)", borderRadius: 8, background: "rgba(8,12,20,0.82)", display: "grid", gap: 8, overflow: "auto" }}>
        <div style={metricLabel}>Local Contacts</div>
        {(currentSystem?.pointsOfInterest ?? []).slice(0, 6).map((poi) => {
          const position = currentSystem ? poiPosition(currentSystem, poi.id) : fallbackPosition(poi.id);
          const selected = session.selectedTarget?.poiId === poi.id;
          return (
            <button
              key={poi.id}
              data-slice-poi={poi.id}
              style={{ ...sliceButton, justifyContent: "space-between", border: selected ? "1px solid rgba(240,160,48,0.82)" : sliceButton.border, color: selected ? "#f0a030" : sliceButton.color }}
              onClick={(event) => {
                event.stopPropagation();
                onPoiTarget(poi, position);
              }}
              onContextMenu={(event) => {
                event.preventDefault();
                event.stopPropagation();
                if (currentSystem) openPoiMenu(event.clientX, event.clientY, currentSystem, poi);
              }}
            >
              <span>{poi.name}</span>
              <span style={{ color: "#64748b", marginLeft: 8 }}>{poi.type.replace(/_/g, " ")}</span>
            </button>
          );
        })}
        {localEntities.map((entity) => (
          <button
            key={entity.id}
            style={{ ...sliceButton, justifyContent: "space-between", border: session.selectedTarget?.id === entity.id ? "1px solid rgba(240,160,48,0.82)" : sliceButton.border, color: entity.type === "hostile" ? "#fca5a5" : sliceButton.color }}
            onClick={(event) => {
              event.stopPropagation();
              selectEntity(entity);
            }}
            onContextMenu={(event) => {
              event.preventDefault();
              event.stopPropagation();
              openEntityMenu(event.clientX, event.clientY, entity);
            }}
          >
            <span>{entity.name}</span>
            <span style={{ color: "#64748b", marginLeft: 8 }}>{entity.type}</span>
          </button>
        ))}
      </div>

      {contextMenu && (
        <div onClick={(event) => event.stopPropagation()} style={{ position: "fixed", left: contextMenu.x, top: contextMenu.y, zIndex: 10, minWidth: 210, background: "rgba(10,16,28,0.97)", border: "1px solid rgba(148,163,184,0.36)", borderRadius: 8, overflow: "hidden", boxShadow: "0 18px 50px rgba(0,0,0,0.35)", fontFamily: "var(--font-mono)", fontSize: 11 }}>
          <div style={{ padding: 10, borderBottom: "1px solid rgba(148,163,184,0.18)" }}>
            <div style={{ color: "#f8fafc", overflowWrap: "anywhere" }}>{contextMenu.title}</div>
            <div style={{ ...metricLabel, marginTop: 3 }}>{contextMenu.subtitle}</div>
          </div>
          {contextMenu.actions.map((action) => (
            <button
              key={action.label}
              style={action.label === "Approach" && !action.disabled ? { ...slicePrimaryButton, width: "100%", justifyContent: "flex-start", border: "0", borderRadius: 0 } : menuButtonStyle}
              disabled={action.disabled}
              onClick={() => {
                action.run();
                setContextMenu(null);
              }}
            >
              {action.label}
            </button>
          ))}
        </div>
      )}
    </section>
  );
}
