import { useMemo } from 'react'
import * as THREE from 'three'
import { truckPath } from '../curves/truckPath'
import { computeTruckProgress } from './useTruckMovement'

/**
 * Fixed camera "stations" along the story. Defined once at module scope so the
 * per-frame solver never re-allocates them.
 */
const VIEWS = {
  firstMileWhole: { position: new THREE.Vector3(38.0, 15.0, -10.0), target: new THREE.Vector3(24.377, 4.0, -39.303) },
  firstMileFront: { position: new THREE.Vector3(7.0, 3.0, -19.0), target: new THREE.Vector3(15.5, 1.5, -26.5) },
  midMile: { position: new THREE.Vector3(-7.0, 7.5, 8.0), target: new THREE.Vector3(-19.146, 2.5, -9.0) },
  lastMileClose: { position: new THREE.Vector3(-3.5, 4.0, 15.0), target: new THREE.Vector3(8.0, 2.0, 20.0) },
  lastMileZoomedOut: { position: new THREE.Vector3(-10.4, 5.2, 12.0), target: new THREE.Vector3(8.0, 2.0, 20.0) },
  analytics: { position: new THREE.Vector3(-13.5, 5.0, 31.0), target: new THREE.Vector3(-7.7, 3.5, 25.4) },
}

// Module-level scratch vectors — reused every frame, zero allocation.
const _truckPos = new THREE.Vector3()
const _forward = new THREE.Vector3()
const _up = new THREE.Vector3(0, 1, 0)
const _right = new THREE.Vector3()
const _cruise1Pos = new THREE.Vector3()
const _cruise2Pos = new THREE.Vector3()

const smoothstep = (a) => a * a * (3 - 2 * a)

/**
 * Solve the camera position + lookAt target for a given scroll progress, writing
 * the result into the supplied vectors. Pure and allocation-free so it can run
 * inside useFrame without ever touching React state. Math is identical to the
 * original useCameraAnimation useMemo — only the storage was hoisted out.
 */
export function computeCameraState(scrollProgress, outPosition, outTarget) {
  const truckProgress = computeTruckProgress(scrollProgress)
  truckPath.getPoint(truckProgress, _truckPos)

  // Local truck axes from the spline tangent (for the follow "cruise" cameras).
  truckPath.getTangent(truckProgress, _forward).normalize()
  _right.crossVectors(_forward, _up).normalize()

  _cruise1Pos.copy(_truckPos).addScaledVector(_forward, 7.2).addScaledVector(_up, 3.2).addScaledVector(_right, -3.0)
  _cruise2Pos.copy(_truckPos).addScaledVector(_forward, 7.2).addScaledVector(_up, 3.2).addScaledVector(_right, 3.0)

  const p = scrollProgress
  if (p < 0.04) {
    outPosition.copy(VIEWS.firstMileWhole.position)
    outTarget.copy(VIEWS.firstMileWhole.target)
  } else if (p < 0.14) {
    const a = smoothstep((p - 0.04) / 0.10)
    outPosition.lerpVectors(VIEWS.firstMileWhole.position, VIEWS.firstMileFront.position, a)
    outTarget.lerpVectors(VIEWS.firstMileWhole.target, VIEWS.firstMileFront.target, a)
  } else if (p < 0.18) {
    const a = smoothstep((p - 0.14) / 0.04)
    outPosition.lerpVectors(VIEWS.firstMileFront.position, _cruise1Pos, a)
    outTarget.lerpVectors(VIEWS.firstMileFront.target, _truckPos, a)
  } else if (p < 0.34) {
    outPosition.copy(_cruise1Pos)
    outTarget.copy(_truckPos)
  } else if (p < 0.38) {
    const a = smoothstep((p - 0.34) / 0.04)
    outPosition.lerpVectors(_cruise1Pos, VIEWS.midMile.position, a)
    outTarget.lerpVectors(_truckPos, VIEWS.midMile.target, a)
  } else if (p < 0.50) {
    outPosition.copy(VIEWS.midMile.position)
    outTarget.copy(VIEWS.midMile.target)
  } else if (p < 0.54) {
    const a = smoothstep((p - 0.50) / 0.04)
    outPosition.lerpVectors(VIEWS.midMile.position, _cruise2Pos, a)
    outTarget.lerpVectors(VIEWS.midMile.target, _truckPos, a)
  } else if (p < 0.72) {
    outPosition.copy(_cruise2Pos)
    outTarget.copy(_truckPos)
  } else if (p < 0.76) {
    const a = smoothstep((p - 0.72) / 0.04)
    outPosition.lerpVectors(_cruise2Pos, VIEWS.lastMileClose.position, a)
    outTarget.lerpVectors(_truckPos, VIEWS.lastMileClose.target, a)
  } else if (p < 0.92) {
    // Last Mile stop sequence: park → zoom out → hold.
    if (p < 0.80) {
      outPosition.copy(VIEWS.lastMileClose.position)
      outTarget.copy(VIEWS.lastMileClose.target)
    } else if (p < 0.84) {
      const a = smoothstep((p - 0.80) / 0.04)
      outPosition.lerpVectors(VIEWS.lastMileClose.position, VIEWS.lastMileZoomedOut.position, a)
      outTarget.lerpVectors(VIEWS.lastMileClose.target, VIEWS.lastMileZoomedOut.target, a)
    } else {
      outPosition.copy(VIEWS.lastMileZoomedOut.position)
      outTarget.copy(VIEWS.lastMileZoomedOut.target)
    }
  } else if (p < 0.96) {
    const a = smoothstep((p - 0.92) / 0.04)
    outPosition.lerpVectors(VIEWS.lastMileZoomedOut.position, VIEWS.analytics.position, a)
    outTarget.lerpVectors(VIEWS.lastMileZoomedOut.target, VIEWS.analytics.target, a)
  } else {
    outPosition.copy(VIEWS.analytics.position)
    outTarget.copy(VIEWS.analytics.target)
  }
}

/**
 * Legacy React hook kept for compatibility. No longer used on the render path
 * (CameraRig computes the state inside useFrame), so it no longer re-renders
 * every scroll frame.
 */
export const useCameraAnimation = (scrollProgress) => {
  return useMemo(() => {
    const position = new THREE.Vector3()
    const target = new THREE.Vector3()
    computeCameraState(scrollProgress, position, target)
    return { position, target }
  }, [scrollProgress])
}

export default useCameraAnimation
