import { useRef } from "react";
import { useFrame } from "@react-three/fiber";
import type { ThreeEvent } from "@react-three/fiber";
import * as THREE from "three";
import { SpaceCanvas } from "../shared/SpaceCanvas";
import { SpaceEnvironment } from "../shared/SpaceEnvironment";
import { CameraRig } from "../shared/CameraRig";
import { ShipMesh } from "../shared/ShipMesh";
import { StationMesh } from "../shared/StationMesh";
import { AsteroidMesh } from "../shared/AsteroidMesh";
import { RouteLine } from "../shared/RouteLine";
import { getSystemPoiPosition } from "../shared/poiOrbit";
import { StarSystemContents } from "../shared/StarSystemContents";
import type { GalaxySystem, SystemPointOfInterest, Vec3 } from "../shared/types";
import type { LocalEntity, LocalWaypoint } from "./movementState";

type MovementSceneProps = {
  currentSystemId: string;
  currentSystem: GalaxySystem | null;
  localEntities: LocalEntity[];
  localWaypoints: LocalWaypoint[];
  shipPosition: Vec3;
  onFrame: (dt: number, elapsedTime: number) => void;
  onWaypointPick: (waypoint: LocalWaypoint) => void;
  onPoiPick: (poi: SystemPointOfInterest, position: Vec3) => void;
  onPoiContext?: (poi: SystemPointOfInterest, position: Vec3, event: ThreeEvent<MouseEvent>) => void;
  onEntityPick?: (entity: LocalEntity, position: Vec3) => void;
  onEntityContext?: (entity: LocalEntity, position: Vec3, event: ThreeEvent<MouseEvent>) => void;
};

export const localEntityPosition = (entity: LocalEntity): Vec3 => [(entity.x - 400) * 0.15, 0, (entity.y - 300) * 0.15];
export const MOVEMENT_SYSTEM_SCALE = 3.2;

function MovementWorld({ currentSystemId, currentSystem, localEntities, localWaypoints, shipPosition, onFrame, onWaypointPick, onPoiPick, onPoiContext, onEntityPick, onEntityContext }: MovementSceneProps) {
  const shipRef = useRef<THREE.Group>(null);
  useFrame((state, dt) => {
    onFrame(dt, state.clock.elapsedTime);
    if (shipRef.current) {
      shipRef.current.position.lerp(new THREE.Vector3(...shipPosition), Math.min(1, dt * 8));
      shipRef.current.position.y += Math.sin(state.clock.elapsedTime * 1.6) * 0.005;
    }
  });

  return (
    <>
      <SpaceEnvironment density={3200} spread={2200} />
      <CameraRig target={shipPosition} orbit distance={58} />
      <gridHelper args={[220, 22, "#0d1520", "#0d1520"]} position={[0, -2, 0]} />
      <mesh
        rotation={[-Math.PI / 2, 0, 0]}
        position={[0, -1.8, 0]}
        onClick={(event) => {
          event.stopPropagation();
          onWaypointPick({
            id: `click-${Date.now()}`,
            name: "Manual nav point",
            type: "manual",
            position: [event.point.x, 0, event.point.z],
          });
        }}
      >
        <planeGeometry args={[210, 210]} />
        <meshBasicMaterial transparent opacity={0} depthWrite={false} />
      </mesh>
      {currentSystem && (
        <StarSystemContents
          systemId={currentSystem.id}
          systemName={currentSystem.name}
          starColor={currentSystem.color}
          planets={currentSystem.planets}
          pointsOfInterest={currentSystem.pointsOfInterest}
          selectedPoiId={localWaypoints[0]?.type === "poi" ? localWaypoints[0].id : null}
          expanded
          scale={MOVEMENT_SYSTEM_SCALE}
          onPoiSelect={(poi, event) => {
            event.stopPropagation();
            const position = getSystemPoiPosition({
              systemId: currentSystem.id,
              planets: currentSystem.planets,
              pointsOfInterest: currentSystem.pointsOfInterest,
              poiId: poi.id,
              scale: MOVEMENT_SYSTEM_SCALE,
              expanded: true,
            });
            onPoiPick(poi, position);
          }}
          onPoiContext={(poi, event) => {
            event.stopPropagation();
            const position = getSystemPoiPosition({
              systemId: currentSystem.id,
              planets: currentSystem.planets,
              pointsOfInterest: currentSystem.pointsOfInterest,
              poiId: poi.id,
              scale: MOVEMENT_SYSTEM_SCALE,
              expanded: true,
            });
            onPoiContext?.(poi, position, event);
          }}
        />
      )}
      <group ref={shipRef} position={shipPosition}>
        <ShipMesh scale={0.18} engineActive={localWaypoints.some((waypoint) => !waypoint.arrived)} />
      </group>
      {localEntities.map((entity) => {
        const position = localEntityPosition(entity);
        return (
          <group key={entity.id} position={position}>
            <group
              onClick={(event) => {
                event.stopPropagation();
                onEntityPick?.(entity, position);
              }}
              onContextMenu={(event) => {
                event.stopPropagation();
                onEntityContext?.(entity, position, event);
              }}
              onPointerOver={(event) => {
                event.stopPropagation();
                document.body.style.cursor = "pointer";
              }}
              onPointerOut={() => {
                document.body.style.cursor = "";
              }}
            >
              {entity.type === "asteroid" ? <AsteroidMesh scale={1.7} /> : entity.type === "station" ? <StationMesh scale={0.8} /> : <ShipMesh scale={0.14} hostile={entity.type === "hostile"} color={entity.type === "hostile" ? "#7f1d1d" : "#1a3a2a"} emissive={entity.type === "hostile" ? "#ef4444" : "#22c55e"} />}
            </group>
          </group>
        );
      })}
      {localWaypoints.length > 0 && <RouteLine points={[shipPosition, ...localWaypoints.map((waypoint) => waypoint.position)]} color="#f0a030" width={2} />}
      {localWaypoints.map((waypoint) => (
        <mesh key={waypoint.id} position={waypoint.position}>
          <sphereGeometry args={[0.8, 16, 16]} />
          <meshBasicMaterial color={waypoint.type === "poi" ? "#f0a030" : "#22d3ee"} />
        </mesh>
      ))}
      {currentSystem && (
        <mesh position={[0, 7.2, -9]}>
          <sphereGeometry args={[0.42, 16, 16]} />
          <meshBasicMaterial color={currentSystem.id === currentSystemId ? "#22c55e" : currentSystem.color} />
        </mesh>
      )}
    </>
  );
}

export function MovementScene(props: MovementSceneProps) {
  return (
    <SpaceCanvas camera={{ position: [18, 18, 32], fov: 55, near: 0.1, far: 5000 }}>
      <MovementWorld {...props} />
    </SpaceCanvas>
  );
}
