import React, { useRef } from 'react'
import { useFrame } from '@react-three/fiber'
import * as THREE from 'three'
import { useSceneStore } from '../store/useSceneStore'
import { computeCameraState } from '../hooks/useCameraAnimation'
import { easing } from 'maath'

/**
 * CameraRig
 * ---------------------------------------------------------------------------
 * PERF: This used to `useSceneStore(s => s.scrollProgress)`, which re-rendered
 * the component (and re-ran the heavy useCameraAnimation useMemo, allocating
 * ~15 Vector3s) on EVERY scroll frame. Now it subscribes to nothing — it reads
 * scroll progress transiently via `getState()` inside the frame loop and solves
 * the camera with an allocation-free pure function writing into reused vectors.
 * Result: zero React renders while scrolling; all motion happens in the rAF loop.
 */
export default function CameraRig() {
  const currentLookAt = useRef(new THREE.Vector3(19.7, 4.4, -31.08))
  const targetPosition = useRef(new THREE.Vector3()).current
  const lookAtTarget = useRef(new THREE.Vector3()).current

  useFrame((state, delta) => {
    const { camera } = state

    // Solve the target camera pose for the current scroll position (read without
    // subscribing — no re-render).
    const scrollProgress = useSceneStore.getState().scrollProgress
    computeCameraState(scrollProgress, targetPosition, lookAtTarget)

    // maath's easing.damp3 divides by delta; a delta of 0 (coincident/first
    // frames) yields NaN that poisons the damper. Clamp to a safe range.
    const dt = Number.isFinite(delta) && delta > 0 ? Math.min(delta, 0.1) : 1 / 60

    easing.damp3(camera.position, targetPosition, 0.35, dt)
    easing.damp3(currentLookAt.current, lookAtTarget, 0.25, dt)

    // Defensive recovery: never let a non-finite value blank the scene.
    if (!Number.isFinite(camera.position.x)) camera.position.copy(targetPosition)
    if (!Number.isFinite(currentLookAt.current.x)) currentLookAt.current.copy(lookAtTarget)

    camera.lookAt(currentLookAt.current)

    // Portrait screens: widen FOV so the truck & buildings stay in frame.
    const aspect = state.size.width / state.size.height
    const fov = aspect < 1.0 ? Math.min(75, 45 / Math.sqrt(aspect)) : 45
    if (camera.fov !== fov) {
      camera.fov = fov
      camera.updateProjectionMatrix()
    }
  })

  return null
}
