import { useEffect, useRef, useState } from "react";
import * as Types from "../../../../types/world/worldTypes";
import { useGLTF } from "@react-three/drei";
import { useFrame, useThree } from "@react-three/fiber";
import { useSelectedEventSphere, useIsDragging, useIsRotating, } from "../../../../store/simulation/useSimulationStore";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { DoubleSide, Group, Plane, Vector3 } from "three";

import startPoint from "../../../../assets/gltf-glb/ui/arrow_green.glb";
import startEnd from "../../../../assets/gltf-glb/ui/arrow_red.glb";
import { useSceneContext } from "../../../scene/sceneContext";
import { useProductContext } from "../../products/productContext";
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../../builder/version/versionContext";

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 { selectedProductStore } = useProductContext();
    const { vehicleStore, productStore } = useSceneContext();
    const { selectedProduct } = selectedProductStore();
    const { vehicles, getVehicleById } = vehicleStore();
    const { updateEvent } = productStore();
    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 { selectedVersionStore } = useVersionContext();
    const { selectedVersion } = selectedVersionStore();
    const { projectId } = useParams();

    const updateBackend = (
        productName: string,
        productUuid: string,
        projectId: string,
        eventData: EventsSchema
    ) => {
        upsertProductOrEventApi({
            productName: productName,
            productUuid: productUuid,
            projectId: projectId,
            eventDatas: eventData,
            versionId: selectedVersion?.versionId || '',
        });
    };

    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, vehicles]);

    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.productUuid,
                    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.productUuid,
                        projectId || '',
                        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;
