import React, { useEffect, useState, useRef } from "react";
import * as THREE from "three";
import { useFrame } from "@react-three/fiber";
import { NavMeshQuery } from "@recast-navigation/core";
import { Line } from "@react-three/drei";

// Define interface for props
interface PathNavigatorProps {
  navMesh: any;
  selectedPoints: any;
}

export default function PathNavigator({
  navMesh,
  selectedPoints,
}: PathNavigatorProps) {
  const [path, setPath] = useState<[number, number, number][]>([]);
  const progressRef = useRef(0);
  const meshRef = useRef<THREE.Mesh | null>(null);

  useEffect(() => {
    if (selectedPoints.length === 2 && navMesh) {
      const [start, end] = selectedPoints;
      if (!start || !end) return;

      const navMeshQuery = new NavMeshQuery(navMesh);

      const { path: computedPath } = navMeshQuery.computePath(start, end);

      if (computedPath.length > 0) {
        setPath(computedPath.map(({ x, y, z }) => [x, y + 0.1, z]));
        progressRef.current = 0;
      }
    }
  }, [selectedPoints, navMesh]);

  useFrame((_, delta) => {
    if (path.length > 1 && meshRef.current) {
      const speed = 3;
      progressRef.current += delta * speed;

      let totalDistance = 0;
      const distances: number[] = [];
      for (let i = 0; i < path.length - 1; i++) {
        const start = new THREE.Vector3(...path[i]);
        const end = new THREE.Vector3(...path[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(...path[index]);
        const end = new THREE.Vector3(...path[index + 1]);
        const segmentDistance = distances[index];

        const t = (coveredDistance - accumulatedDistance) / segmentDistance;
        const position = start.clone().lerp(end, t); // Use clone() to avoid mutating the original vector
        meshRef.current.position.copy(position);

        const direction = new THREE.Vector3()
          .subVectors(end, start)
          .normalize();
        const targetQuaternion = new THREE.Quaternion().setFromUnitVectors(
          new THREE.Vector3(0, 0, 1),
          direction
        );
        meshRef.current.quaternion.slerp(targetQuaternion, 0.1);
      } else {
        progressRef.current = totalDistance;
      }
    }
  });

  return (
    <>
      {path.length > 0 && <Line points={path} color="blue" lineWidth={3} />}
      {path.length > 0 && (
        <mesh ref={meshRef} position={path.length > 0 ? path[0] : [0, 0.1, 0]}>
          <boxGeometry args={[1, 1, 1]} />
          <meshNormalMaterial />
        </mesh>
      )}
    </>
  );
}
