import { useEffect, useRef, useState } from "react";
import * as Types from "../../../../types/world/worldTypes";
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
import startEnd from "../../../../assets/gltf-glb/arrow_red.glb";
import { useGLTF } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import {
  useSelectedEventSphere,
  useIsDragging,
  useSelectedProduct,
  useIsRotating,
} from "../../../../store/simulation/useSimulationStore";
import { useVehicleStore } from "../../../../store/simulation/useVehicleStore";
import { useProductStore } from "../../../../store/simulation/useProductStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/UpsertProductOrEventApi";
import { DoubleSide, Group, Plane, Vector3 } from "three";

const VehicleUI = () => {
  const { scene: startScene } = useGLTF(startPoint) as any;
  const { scene: endScene } = useGLTF(startEnd) as any;
  const startMarker = useRef<Group>(null);
  const endMarker = useRef<Group>(null);
  const prevMousePos = useRef({ x: 0, y: 0 });
  const { selectedEventSphere } = useSelectedEventSphere();
  const { selectedProduct } = useSelectedProduct();
  const { getVehicleById } = useVehicleStore();
  const { updateEvent } = useProductStore();
  const [startPosition, setStartPosition] = useState<[number, number, number]>([
    0, 1, 0,
  ]);

  const [endPosition, setEndPosition] = useState<[number, number, number]>([
    0, 1, 0,
  ]);
  const [startRotation, setStartRotation] = useState<[number, number, number]>([
    0, 0, 0,
  ]);

  const [endRotation, setEndRotation] = useState<[number, number, number]>([
    0, 0, 0,
  ]);
  const [steeringRotation, setSteeringRotation] = useState<
    [number, number, number]
  >([0, 0, 0]);

  const { isDragging, setIsDragging } = useIsDragging();
  const { isRotating, setIsRotating } = useIsRotating();
  const { raycaster } = useThree();
  const [point, setPoint] = useState<[number, number, number]>([0, 0, 0]);
  const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));
  const [tubeRotation, setTubeRotation] = useState<boolean>(false);
  const tubeRef = useRef<Group>(null);
  const outerGroup = useRef<Group>(null);
  const state: Types.ThreeState = useThree();
  const controls: any = state.controls;
  const [selectedVehicleData, setSelectedVechicleData] = useState<{
    position: [number, number, number];
    rotation: [number, number, number];
  }>({ position: [0, 0, 0], rotation: [0, 0, 0] });
  const CIRCLE_RADIUS = 0.8;
  const email = localStorage.getItem("email");
  const organization = email!.split("@")[1].split(".")[0];

  const updateBackend = (
    productName: string,
    productId: string,
    organization: string,
    eventData: EventsSchema
  ) => {
    upsertProductOrEventApi({
      productName: productName,
      productId: productId,
      organization: organization,
      eventDatas: eventData,
    });
  };

  useEffect(() => {
    if (!selectedEventSphere) return;
    const selectedVehicle = getVehicleById(
      selectedEventSphere.userData.modelUuid
    );

    if (selectedVehicle) {
      setSelectedVechicleData({
        position: selectedVehicle.position,
        rotation: selectedVehicle.rotation,
      });
      setPoint(selectedVehicle.point.position);
    }

    setTimeout(() => {
      if (selectedVehicle?.point?.action) {
        const { pickUpPoint, unLoadPoint, steeringAngle } =
          selectedVehicle.point.action;

        if (pickUpPoint && outerGroup.current) {
          const worldPos = new Vector3(
            pickUpPoint.position.x,
            pickUpPoint.position.y,
            pickUpPoint.position.z
          );
          const localPosition = outerGroup.current.worldToLocal(
            worldPos.clone()
          );

          setStartPosition([
            localPosition.x,
            selectedVehicle.point.position[1],
            localPosition.z,
          ]);
          setStartRotation([
            pickUpPoint.rotation.x,
            pickUpPoint.rotation.y,
            pickUpPoint.rotation.z,
          ]);
        } else {
          setStartPosition([0, selectedVehicle.point.position[1] + 0.1, 1.5]);
          setStartRotation([0, 0, 0]);
        }
        // end point
        if (unLoadPoint && outerGroup.current) {
          const worldPos = new Vector3(
            unLoadPoint.position.x,
            unLoadPoint.position.y,
            unLoadPoint.position.z
          );
          const localPosition = outerGroup.current.worldToLocal(worldPos);

          setEndPosition([
            localPosition.x,
            selectedVehicle.point.position[1],
            localPosition.z,
          ]);
          setEndRotation([
            unLoadPoint.rotation.x,
            unLoadPoint.rotation.y,
            unLoadPoint.rotation.z,
          ]);
        } else {
          setEndPosition([0, selectedVehicle.point.position[1] + 0.1, -1.5]);
          setEndRotation([0, 0, 0]);
        }
        setSteeringRotation([0, steeringAngle, 0]);
      }
    }, 10);
  }, [selectedEventSphere, outerGroup.current]);

  const handlePointerDown = (
    e: any,
    state: "start" | "end",
    rotation: "start" | "end"
  ) => {
    if (e.object.name === "handle") {
      const normalizedX = (e.clientX / window.innerWidth) * 2 - 1;
      const normalizedY = -(e.clientY / window.innerHeight) * 2 + 1;
      prevMousePos.current = { x: normalizedX, y: normalizedY };
      setIsRotating(rotation);
      if (controls) controls.enabled = false;
      setIsDragging(null);
    } else {
      setIsDragging(state);
      setIsRotating(null);
      if (controls) controls.enabled = false;
    }
  };

  const handlePointerUp = () => {
    controls.enabled = true;
    setIsDragging(null);
    setIsRotating(null);

    if (selectedEventSphere?.userData.modelUuid) {
      const updatedVehicle = getVehicleById(
        selectedEventSphere.userData.modelUuid
      );

      let globalStartPosition = null;
      let globalEndPosition = null;

      if (outerGroup.current && startMarker.current && endMarker.current) {
        const worldPosStart = new Vector3(...startPosition);
        globalStartPosition = outerGroup.current.localToWorld(
          worldPosStart.clone()
        );
        const worldPosEnd = new Vector3(...endPosition);
        globalEndPosition = outerGroup.current.localToWorld(
          worldPosEnd.clone()
        );
      }
      if (updatedVehicle && globalEndPosition && globalStartPosition) {
        const event = updateEvent(
          selectedProduct.productId,
          selectedEventSphere.userData.modelUuid,
          {
            point: {
              ...updatedVehicle.point,
              action: {
                ...updatedVehicle.point?.action,
                pickUpPoint: {
                  position: {
                    x: globalStartPosition.x,
                    y: 0,
                    z: globalStartPosition.z,
                  },
                  rotation: { x: 0, y: startRotation[1], z: 0 },
                },
                unLoadPoint: {
                  position: {
                    x: globalEndPosition.x,
                    y: 0,
                    z: globalEndPosition.z,
                  },
                  rotation: { x: 0, y: endRotation[1], z: 0 },
                },
                steeringAngle: steeringRotation[1],
              },
            },
          }
        );

        if (event) {
          updateBackend(
            selectedProduct.productName,
            selectedProduct.productId,
            organization,
            event
          );
        }
      }
    }
  };

  useFrame(() => {
    if (!isDragging || !plane.current || !raycaster || !outerGroup.current)
      return;
    const intersectPoint = new Vector3();
    const intersects = raycaster.ray.intersectPlane(
      plane.current,
      intersectPoint
    );
    if (!intersects) return;
    const localPoint = outerGroup?.current.worldToLocal(intersectPoint.clone());
    if (isDragging === "start") {
      setStartPosition([localPoint.x, point[1], localPoint.z]);
    } else if (isDragging === "end") {
      setEndPosition([localPoint.x, point[1], localPoint.z]);
    }
  });

  useEffect(() => {
    const handleGlobalPointerUp = () => {
      setIsDragging(null);
      setIsRotating(null);
      setTubeRotation(false);
      if (controls) controls.enabled = true;
      handlePointerUp();
    };

    if (isDragging || isRotating || tubeRotation) {
      window.addEventListener("pointerup", handleGlobalPointerUp);
    }

    return () => {
      window.removeEventListener("pointerup", handleGlobalPointerUp);
    };
  }, [
    isDragging,
    isRotating,
    startPosition,
    startRotation,
    endPosition,
    endRotation,
    tubeRotation,
    steeringRotation,
    outerGroup.current,
    tubeRef.current,
  ]);

  const prevSteeringY = useRef(0);
  useFrame((state) => {
    if (tubeRotation) {
      const currentPointerX = state.pointer.x;
      const deltaX = currentPointerX - prevMousePos.current.x;
      prevMousePos.current.x = currentPointerX;

      const marker = tubeRef.current;
      if (marker) {
        const rotationSpeed = 2;
        marker.rotation.y += deltaX * rotationSpeed;
        setSteeringRotation([
          marker.rotation.x,
          marker.rotation.y,
          marker.rotation.z,
        ]);
      }
    } else {
      prevSteeringY.current = 0;
    }
  });
  useFrame((state) => {
    if (!isRotating) return;
    const currentPointerX = state.pointer.x;
    const deltaX = currentPointerX - prevMousePos.current.x;
    prevMousePos.current.x = currentPointerX;
    const marker =
      isRotating === "start" ? startMarker.current : endMarker.current;
    if (marker) {
      const rotationSpeed = 10;
      marker.rotation.y += deltaX * rotationSpeed;
      if (isRotating === "start") {
        setStartRotation([
          marker.rotation.x,
          marker.rotation.y,
          marker.rotation.z,
        ]);
      } else {
        setEndRotation([
          marker.rotation.x,
          marker.rotation.y,
          marker.rotation.z,
        ]);
      }
    }
  });

  return selectedVehicleData ? (
    <group
      position={selectedVehicleData.position}
      rotation={selectedVehicleData.rotation}
      ref={outerGroup}
    >
      <group
        position={[0, 0, 0]}
        ref={tubeRef}
        rotation={steeringRotation}
        onPointerDown={(e) => {
          e.stopPropagation();
          setTubeRotation(true);
          prevMousePos.current.x = e.pointer.x;
          controls.enabled = false;
        }}
        onPointerMissed={() => {
          controls.enabled = true;
          setTubeRotation(false);
        }}
        onPointerUp={() => {
          controls.enabled = true;
          setTubeRotation(false);
        }}
      >
        (
        <mesh
          position={[0, point[1], 0]}
          rotation={[-Math.PI / 2, 0, 0]}
          name="steering"
        >
          <ringGeometry args={[CIRCLE_RADIUS, CIRCLE_RADIUS + 0.2, 36]} />
          <meshBasicMaterial color="yellow" side={DoubleSide} />
        </mesh>
        <mesh
          position={[0, point[1], CIRCLE_RADIUS + 0.24]}
          rotation={[Math.PI / 2, 0, 0]}
        >
          <coneGeometry args={[0.1, 0.3, 12]} />
          <meshBasicMaterial color="yellow" side={DoubleSide} />
        </mesh>
        )
      </group>

      {/* Start Marker */}
      <primitive
        name="startMarker"
        object={startScene}
        ref={startMarker}
        position={startPosition}
        rotation={startRotation}
        onPointerDown={(e: any) => {
          e.stopPropagation();
          handlePointerDown(e, "start", "start");
        }}
        onPointerMissed={() => {
          controls.enabled = true;
          setIsDragging(null);
          setIsRotating(null);
        }}
      />

      {/* End Marker */}
      <primitive
        name="endMarker"
        object={endScene}
        ref={endMarker}
        position={endPosition}
        rotation={endRotation}
        onPointerDown={(e: any) => {
          e.stopPropagation();
          handlePointerDown(e, "end", "end");
        }}
        onPointerMissed={() => {
          controls.enabled = true;
          setIsDragging(null);
          setIsRotating(null);
        }}
      />
    </group>
  ) : null;
};
export default VehicleUI;
