import { useEffect, useRef, useState } from 'react'
import { useFrame, useThree } from '@react-three/fiber';
import { useFloorItems } from '../../../../../store/store';
import * as THREE from 'three';
import { Line } from '@react-three/drei';
import { useAnimationPlaySpeed, usePauseButtonStore, useResetButtonStore } from '../../../../../store/usePlayButtonStore';
import { useVehicleStore } from '../../../../../store/simulation/useVehicleStore';

interface VehicleAnimatorProps {
  path: [number, number, number][];
  handleCallBack: () => void;
  currentPhase: string;
  agvUuid: number;
  agvDetail: any;
}

function VehicleAnimator({ path, handleCallBack, currentPhase, agvUuid, agvDetail }: VehicleAnimatorProps) {
  const { decrementVehicleLoad, vehicles } = useVehicleStore();
  const { isPaused } = usePauseButtonStore();
  const { speed } = useAnimationPlaySpeed();
  const { isReset } = useResetButtonStore();
  const [restRotation, setRestingRotation] = useState<boolean>(true);
  const [progress, setProgress] = useState<number>(0);
  const [currentPath, setCurrentPath] = useState<[number, number, number][]>([]);
  const { scene } = useThree();
  const progressRef = useRef<number>(0);
  const movingForward = useRef<boolean>(true);
  const completedRef = useRef<boolean>(false);
  let startTime: number;
  let pausedTime: number;
  let fixedInterval: number;

  useEffect(() => {
    if (currentPhase === 'stationed-pickup' && path.length > 0) {
      setCurrentPath(path);
    } else if (currentPhase === 'pickup-drop' && path.length > 0) {
      setCurrentPath(path);
    } else if (currentPhase === 'drop-pickup' && path.length > 0) {
      setCurrentPath(path);
    }
  }, [currentPhase, path]);

  useEffect(() => {
    setProgress(0);
    completedRef.current = false;
  }, [currentPath]);

  useFrame((_, delta) => {
    const object = scene.getObjectByProperty('uuid', agvUuid);
    if (!object || currentPath.length < 2) return;
    if (isPaused) return;

    let totalDistance = 0;
    const distances = [];

    for (let i = 0; i < currentPath.length - 1; i++) {
      const start = new THREE.Vector3(...currentPath[i]);
      const end = new THREE.Vector3(...currentPath[i + 1]);
      const segmentDistance = start.distanceTo(end);
      distances.push(segmentDistance);
      totalDistance += segmentDistance;
    }

    let coveredDistance = progressRef.current;
    let accumulatedDistance = 0;
    let index = 0;

    while (
      index < distances.length &&
      coveredDistance > accumulatedDistance + distances[index]
    ) {
      accumulatedDistance += distances[index];
      index++;
    }

    if (index < distances.length) {
      const start = new THREE.Vector3(...currentPath[index]);
      const end = new THREE.Vector3(...currentPath[index + 1]);
      const segmentDistance = distances[index];

      const currentDirection = new THREE.Vector3().subVectors(end, start).normalize();
      const targetAngle = Math.atan2(currentDirection.x, currentDirection.z);
      const rotationSpeed = 2.0;
      const currentAngle = object.rotation.y;

      let angleDifference = targetAngle - currentAngle;
      if (angleDifference > Math.PI) angleDifference -= 2 * Math.PI;
      if (angleDifference < -Math.PI) angleDifference += 2 * Math.PI;

      const maxRotationStep = rotationSpeed * delta;
      object.rotation.y += Math.sign(angleDifference) * Math.min(Math.abs(angleDifference), maxRotationStep);

      const isAligned = Math.abs(angleDifference) < 0.01;

      if (isAligned) {
        progressRef.current += delta * (speed * agvDetail.speed);
        coveredDistance = progressRef.current;

        const t = (coveredDistance - accumulatedDistance) / segmentDistance;
        const position = start.clone().lerp(end, t);
        object.position.copy(position);
      }
    }

    if (progressRef.current >= totalDistance) {
      if (restRotation) {
        const targetQuaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, 0, 0));
        object.quaternion.slerp(targetQuaternion, delta * 2);
        const angleDiff = object.quaternion.angleTo(targetQuaternion);
        if (angleDiff < 0.01) {
          let objectRotation = agvDetail.point.rotation
          object.rotation.set(objectRotation[0], objectRotation[1], objectRotation[2]);
          setRestingRotation(false);
        }
        return;
      }
    }

    if (progressRef.current >= totalDistance) {
      setRestingRotation(true);
      progressRef.current = 0;
      movingForward.current = !movingForward.current;
      setCurrentPath([]);
      handleCallBack();
      if (currentPhase === 'pickup-drop') {
        requestAnimationFrame(firstFrame);
      }
    }
  });

  function firstFrame() {
    const unLoadDuration = agvDetail.point.action.unLoadDuration;
    const droppedMaterial = agvDetail.currentLoad;
    fixedInterval = (unLoadDuration / droppedMaterial) * 1000;
    startTime = performance.now();
    step(droppedMaterial);
  }

  function step(droppedMaterial: number) {
    const elapsedTime = performance.now() - startTime;

    if (elapsedTime >= fixedInterval) {
      console.log('fixedInterval: ', fixedInterval);
      console.log('elapsedTime: ', elapsedTime);
      let droppedMat = droppedMaterial - 1;
      decrementVehicleLoad(agvDetail.modelUuid, 1);
      if (droppedMat === 0) return;
      startTime = performance.now();
      requestAnimationFrame(() => step(droppedMat));
    } else {
      requestAnimationFrame(() => step(droppedMaterial));
    }
  }

  return (
    <>
      {currentPath.length > 0 && (
        <>
          <Line points={currentPath} color="blue" lineWidth={3} />
          {currentPath.map((point, index) => (
            <mesh key={index} position={point}>
              <sphereGeometry args={[0.1, 16, 16]} />
              <meshStandardMaterial color="red" />
            </mesh>
          ))}
        </>
      )}
    </>
  );
}

export default VehicleAnimator;