import { useMemo, useRef, useEffect } from 'react'
import { Canvas, useFrame, useThree } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import * as THREE from 'three'

// ── Single body section ────────────────────────────────────────────────
// Renders a CylinderGeometry segment centred at yCenter on the world Y axis.
// rTop = radius at +Y cap, rBot = radius at −Y cap.
function Section({ yCenter, yLen, rTop, rBot, color, opacity = 1 }) {
  const geo = useMemo(
    () => new THREE.CylinderGeometry(
      Math.max(rTop, 0.0001),
      Math.max(rBot, 0.0001),
      yLen, 48, 1, false,
    ),
    [rTop, rBot, yLen],
  )
  return (
    <mesh geometry={geo} position={[0, yCenter, 0]}>
      <meshStandardMaterial
        color={color}
        metalness={0.45}
        roughness={0.5}
        side={THREE.DoubleSide}
        transparent={opacity < 1}
        opacity={opacity}
        depthWrite={opacity >= 1}
      />
    </mesh>
  )
}

// ── Domed tank section ─────────────────────────────────────────────────
// Renders a cylindrical tank with hemispherical domes on both ends.
// yCenter = center of the entire tank, L_cyl = cylindrical body length, R = radius
function TankSection({ yCenter, L_cyl, R, color, opacity = 1 }) {
  const cylGeo = useMemo(
    () => new THREE.CylinderGeometry(R, R, L_cyl, 48, 1, false),
    [R, L_cyl],
  )

  // Top dome: hemisphere pointing upward (positive Y)
  const topDomeGeo = useMemo(
    () => new THREE.SphereGeometry(R, 32, 16, 0, Math.PI * 2, 0, Math.PI / 2),
    [R],
  )

  // Bottom dome: hemisphere pointing downward (negative Y)
  const botDomeGeo = useMemo(
    () => new THREE.SphereGeometry(R, 32, 16, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2),
    [R],
  )

  const material = (
    <meshStandardMaterial
      color={color}
      metalness={0.45}
      roughness={0.5}
      side={THREE.DoubleSide}
      transparent={opacity < 1}
      opacity={opacity}
      depthWrite={opacity >= 1}
    />
  )

  return (
    <>
      {/* Cylindrical body */}
      <mesh geometry={cylGeo} position={[0, yCenter, 0]}>
        {material}
      </mesh>
      {/* Top dome */}
      <mesh geometry={topDomeGeo} position={[0, yCenter + L_cyl / 2 + R / 2, 0]}>
        {material}
      </mesh>
      {/* Bottom dome */}
      <mesh geometry={botDomeGeo} position={[0, yCenter - L_cyl / 2 - R / 2, 0]}>
        {material}
      </mesh>
    </>
  )
}

// ── Nose cone with profile (LatheGeometry) ────────────────────────────────
// Uses profile points {x, r} to generate a smooth surface of revolution.
// x is mapped to height (y-axis), r is the radius at each point.
// Height is inverted so tip (r=0) ends up at the top of the rocket.
function NoseCone({ yCenter, profilePoints, color, opacity = 1 }) {
  const geo = useMemo(() => {
    if (!profilePoints || profilePoints.length < 2) return null

    const L = profilePoints[profilePoints.length - 1].x
    // Map points so height = L - x (inverted), so tip (x=0) becomes height L
    // This makes tip point upward when positioned in the rocket
    const curvePoints = profilePoints.map(p => new THREE.Vector2(p.r, L - p.x))

    return new THREE.LatheGeometry(curvePoints, 32)
  }, [profilePoints])

  if (!geo) return null

  const L = profilePoints[profilePoints.length - 1].x
  return (
    <mesh geometry={geo} position={[0, yCenter - L / 2, 0]}>
      <meshStandardMaterial
        color={color}
        metalness={0.45}
        roughness={0.5}
        side={THREE.DoubleSide}
        transparent={opacity < 1}
        opacity={opacity}
        depthWrite={opacity >= 1}
      />
    </mesh>
  )
}

// ── Rocket composed of stacked vertical sections ───────────────────────
// +Y = nose tip (up)   −Y = nozzle exit (down / toward ground)
function RocketShape({ geometry: geo }) {
  const groupRef = useRef()

  // Slow spin around vertical axis
  useFrame((_, delta) => {
    if (groupRef.current) groupRef.current.rotation.y += delta * 0.18
  })

  if (!geo) return null

  const {
    outerRadius: R,
    L_nose, L_payload, L_tank, L_tank_fuel, L_tank_ox, L_engine,
    totalLength, r_inner, arrangement, innerPropellant, noseProfilePoints,
  } = geo

  const mid      = totalLength / 2
  const tankY0   = L_nose + L_payload
  const engineY0 = tankY0 + L_tank

  // Map rocket-space distance from nose tip → world Y.
  // Flips so nose = +Y (top) and engine exit = −Y (bottom).
  const yc = (y0, h) => mid - y0 - h / 2

  return (
    <group ref={groupRef}>

      {/* Nose cone — profile-based shape */}
      {noseProfilePoints && noseProfilePoints.length > 0 ? (
        <NoseCone
          yCenter={yc(0, L_nose)}
          profilePoints={noseProfilePoints}
          color="#94a3b8"
        />
      ) : (
        <Section
          yCenter={yc(0, L_nose)} yLen={L_nose}
          rTop={0.001} rBot={R}
          color="#94a3b8"
        />
      )}

      {/* Payload bay */}
      {L_payload > 0 && (
        <Section
          yCenter={yc(L_nose, L_payload)} yLen={L_payload}
          rTop={R} rBot={R}
          color="#6366f1"
        />
      )}

      {/* Tanks — tandem: oxidizer above fuel (with domes) */}
      {arrangement === 'tandem' && L_tank_ox_cyl > 0 && (
        <TankSection
          yCenter={yc(tankY0, L_tank_ox)} L_cyl={L_tank_ox_cyl}
          R={R}
          color="#06b6d4"
        />
      )}
      {arrangement === 'tandem' && L_tank_fuel_cyl > 0 && (
        <TankSection
          yCenter={yc(tankY0 + L_tank_ox, L_tank_fuel)} L_cyl={L_tank_fuel_cyl}
          R={R}
          color="#f59e0b"
        />
      )}

      {/* Tanks — coaxial: semi-transparent outer + solid inner */}
      {arrangement === 'coaxial' && L_tank > 0 && (
        <>
          <Section
            yCenter={yc(tankY0, L_tank)} yLen={L_tank}
            rTop={R} rBot={R}
            color={innerPropellant === 'fuel' ? '#06b6d4' : '#f59e0b'}
            opacity={0.55}
          />
          {r_inner > 0 && (
            <Section
              yCenter={yc(tankY0, L_tank)} yLen={L_tank}
              rTop={r_inner} rBot={r_inner}
              color={innerPropellant === 'fuel' ? '#f59e0b' : '#06b6d4'}
            />
          )}
        </>
      )}

      {/* Engine — converging (chamber) section: body width → throat */}
      {L_engine > 0 && geo.nozzleThroatRadius > 0 && geo.chamberLength > 0 && (
        <Section
          yCenter={yc(engineY0, geo.chamberLength)} yLen={geo.chamberLength}
          rTop={R} rBot={geo.nozzleThroatRadius}
          color="#3b82f6"
        />
      )}
      {/* Engine — diverging (nozzle bell) section: throat → exit (always flares downward) */}
      {L_engine > 0 && geo.nozzleThroatRadius > 0 && geo.nozzleLength > 0 && (
        <Section
          yCenter={yc(engineY0 + geo.chamberLength, geo.nozzleLength)} yLen={geo.nozzleLength}
          rTop={geo.nozzleThroatRadius} rBot={geo.nozzleExitRadius ?? R * 1.3}
          color="#3b82f6"
        />
      )}
      {/* Engine — fallback when detailed geometry not available */}
      {L_engine > 0 && !(geo.nozzleThroatRadius > 0) && (
        <Section
          yCenter={yc(engineY0, L_engine)} yLen={L_engine}
          rTop={R} rBot={R * 1.3}
          color="#3b82f6"
        />
      )}

    </group>
  )
}

// ── Camera auto-fit ────────────────────────────────────────────────────
function CameraRig({ geometry: geo }) {
  const { camera, controls } = useThree()

  useEffect(() => {
    if (!geo) return
    const span = Math.max(geo.totalLength, geo.outerRadius * 2)
    const dist = span * 2.2
    camera.position.set(dist * 0.7, dist * 0.25, dist * 0.7)
    camera.near = dist * 0.001
    camera.far  = dist * 10
    camera.updateProjectionMatrix()
    if (controls) {
      controls.target.set(0, 0, 0)
      controls.update()
    } else {
      camera.lookAt(0, 0, 0)
    }
  }, [geo, camera, controls])

  return null
}

function Scene({ geometry }) {
  return (
    <>
      <ambientLight intensity={0.6} />
      <directionalLight position={[5, 8, 5]}   intensity={1.4} />
      <directionalLight position={[-4, -4, -4]} intensity={0.3} />
      <RocketShape geometry={geometry} />
      <OrbitControls makeDefault enablePan={false} />
      <CameraRig geometry={geometry} />
    </>
  )
}

export default function RocketModel3D({ geometry }) {
  return (
    <div className="relative w-full h-full">
      {!geometry && (
        <div className="absolute inset-0 flex flex-col items-center justify-center text-center pointer-events-none z-10">
          <div className="text-5xl mb-4 opacity-20">🚀</div>
          <p className="text-slate-500 text-sm leading-relaxed">
            Import an engine and enter an outer diameter<br />to see the 3D rocket
          </p>
        </div>
      )}
      <Canvas
        camera={{ position: [0.5, 0.3, 0.8], fov: 45 }}
        style={{ background: 'transparent' }}
      >
        <Scene geometry={geometry} />
      </Canvas>
    </div>
  )
}
