/**
 * CameraController - handles camera movement and focus
 */
import { useEffect, useRef } from 'react';
import { useFrame, useThree } from '@react-three/fiber';
import { Vector3 } from 'three';
import type { CelestialBody } from '../types';
import { calculateRenderPosition, findParentPlanet } from '../utils/renderPosition';

interface CameraControllerProps {
  focusTarget: CelestialBody | null;
  allBodies: CelestialBody[];
  onAnimationComplete?: () => void;
  resetTrigger?: number;
  defaultPosition?: [number, number, number];
}

export function CameraController({ 
  focusTarget, 
  allBodies, 
  onAnimationComplete, 
  resetTrigger = 0,
  defaultPosition = [10, 8, 10] // Default closer to inner solar system
}: CameraControllerProps) {
  const { camera } = useThree();
  const targetPosition = useRef(new Vector3());
  const isAnimating = useRef(false);
  const isResetting = useRef(false);
  const animationProgress = useRef(0);
  const startPosition = useRef(new Vector3());
  const lastResetTrigger = useRef(0);

  // Handle manual reset trigger
  useEffect(() => {
    if (resetTrigger !== lastResetTrigger.current) {
      lastResetTrigger.current = resetTrigger;
      // Force reset
      targetPosition.current.set(...defaultPosition);
      startPosition.current.copy(camera.position);
      isAnimating.current = true;
      isResetting.current = true;
      animationProgress.current = 0;
    }
  }, [resetTrigger, camera, defaultPosition]); // Only run when resetTrigger changes

  // Handle focus target changes
  useEffect(() => {
    if (focusTarget) {
      isResetting.current = false; // Cancel reset if target selected
      
      // Focus on target - use smart rendered position
      const renderPos = calculateRenderPosition(focusTarget, allBodies);
      const currentTargetPos = new Vector3(renderPos.x, renderPos.z, renderPos.y);

      // Calculate ideal camera position based on target
      const pos = focusTarget.positions[0];
      const distance = Math.sqrt(pos.x ** 2 + pos.y ** 2 + pos.z ** 2);
      const parentInfo = findParentPlanet(focusTarget, allBodies);

      let offset: number;
      let heightMultiplier = 1;
      let sideMultiplier = 1;

      if (focusTarget.type === 'planet') {
        offset = 4;
        heightMultiplier = 1.5;
        sideMultiplier = 1;
      } else if (focusTarget.type === 'probe') {
        if (parentInfo) {
          offset = 3;
          heightMultiplier = 0.8;
          sideMultiplier = 1.2;
        } else if (distance < 10) {
          offset = 5;
          heightMultiplier = 0.6;
          sideMultiplier = 1.5;
        } else if (distance > 50) {
          offset = 4;
          heightMultiplier = 0.8;
          sideMultiplier = 1;
        } else {
          offset = 6;
          heightMultiplier = 0.8;
          sideMultiplier = 1.2;
        }
      } else {
        offset = 10;
        heightMultiplier = 1;
        sideMultiplier = 1;
      }

      targetPosition.current.set(
        currentTargetPos.x + (offset * sideMultiplier),
        currentTargetPos.y + (offset * heightMultiplier),
        currentTargetPos.z + offset
      );

      // Start animation to target
      startPosition.current.copy(camera.position);
      isAnimating.current = true;
      animationProgress.current = 0;

    } else {
      // Target became null (e.g. info window closed)
      // Only stop animation if we are NOT in the middle of a reset
      if (!isResetting.current && isAnimating.current) {
        isAnimating.current = false;
        animationProgress.current = 0;
      }
    }
  }, [focusTarget, allBodies, camera]);

  useFrame((_, delta) => {
    if (isAnimating.current) {
      // Smooth animation using easing
      animationProgress.current += delta * 0.8; // Animation speed

      if (animationProgress.current >= 1) {
        animationProgress.current = 1;
        isAnimating.current = false;
        isResetting.current = false; // Animation done
        if (onAnimationComplete) onAnimationComplete();
      }

      // Easing function (ease-in-out)
      const t = animationProgress.current;
      const eased = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;

      // Interpolate camera position
      camera.position.lerpVectors(startPosition.current, targetPosition.current, eased);

      // Look at target - use smart rendered position (only during animation)
      if (focusTarget) {
        const renderPos = calculateRenderPosition(focusTarget, allBodies);
        camera.lookAt(renderPos.x, renderPos.z, renderPos.y);
      } else {
        camera.lookAt(0, 0, 0);
      }
    }
    // After animation completes, OrbitControls will take over
  });

  return null;
}
