import React, { useEffect, useRef, useState } from 'react';
import * as Types from "../../../../types/world/worldTypes";
import startPoint from "../../../../assets/gltf-glb/arrow_green.glb";
import * as THREE from "three";
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, useIsRotating } from '../../../../store/simulation/useSimulationStore';
import { useVehicleStore } from '../../../../store/simulation/useVehicleStore';
import { useProductStore } from '../../../../store/simulation/useProductStore';
import { useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';

const VehicleUI = () => {
    const { scene: startScene } = useGLTF(startPoint) as any;
    const { scene: endScene } = useGLTF(startEnd) as any;
    const startMarker = useRef<THREE.Group>(null);
    const endMarker = useRef<THREE.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, 0, 0]);
    const [endPosition, setEndPosition] = useState<[number, number, number]>([0, 0, 0]);
    const [startRotation, setStartRotation] = useState<[number, number, number]>([0, 0, 0]);
    const [endRotation, setEndRotation] = useState<[number, number, number]>([0, 0, 0]);
    const { isDragging, setIsDragging } = useIsDragging();
    const { isRotating, setIsRotating } = useIsRotating();
    const { raycaster } = useThree();
    const plane = useRef(new THREE.Plane(new THREE.Vector3(0, 1, 0), 0));
    const state: Types.ThreeState = useThree();
    const controls: any = state.controls;

    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?.point?.action) {
            const { pickUpPoint, unLoadPoint } = selectedVehicle.point.action;

            if (pickUpPoint) {
                setStartPosition([pickUpPoint.position.x, 0, pickUpPoint.position.z]);
                setStartRotation([pickUpPoint.rotation.x, pickUpPoint.rotation.y, pickUpPoint.rotation.z]);
            } else {
                const defaultLocal = new THREE.Vector3(0, 0, 1.5);
                const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
                setStartPosition([defaultWorld.x, 0, defaultWorld.z]);
                setStartRotation([0, 0, 0]);
            }

            if (unLoadPoint) {
                setEndPosition([unLoadPoint.position.x, 0, unLoadPoint.position.z]);
                setEndRotation([unLoadPoint.rotation.x, unLoadPoint.rotation.y, unLoadPoint.rotation.z]);
            } else {
                const defaultLocal = new THREE.Vector3(0, 0, -1.5);
                const defaultWorld = selectedEventSphere.localToWorld(defaultLocal);
                setEndPosition([defaultWorld.x, 0, defaultWorld.z]);
                setEndRotation([0, 0, 0]);
            }
        }
    }, [selectedEventSphere]);

    useFrame(() => {
        if (!isDragging) return;
        const intersectPoint = new THREE.Vector3();
        const intersects = raycaster.ray.intersectPlane(plane.current, intersectPoint);

        if (intersects) {
            if (isDragging === "start") {
                setStartPosition([intersectPoint.x, 0, intersectPoint.z]);
            }
            if (isDragging === "end") {
                setEndPosition([intersectPoint.x, 0, intersectPoint.z]);
            }
        }
    });

    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;
            if (isRotating === 'start') {
                const y = startRotation[1] + deltaX * rotationSpeed;
                setStartRotation([0, y, 0]);
            } else {
                const y = endRotation[1] + deltaX * rotationSpeed;
                setEndRotation([0, y, 0]);
            }
        }
    });


    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);

            if (updatedVehicle) {
                const event = updateEvent(selectedProduct.productId, selectedEventSphere.userData.modelUuid, {
                    point: {
                        ...updatedVehicle.point,
                        action: {
                            ...updatedVehicle.point?.action,
                            pickUpPoint: {
                                position: { x: startPosition[0], y: startPosition[1], z: startPosition[2], },
                                rotation: { x: 0, y: startRotation[1], z: 0, },
                            },
                            unLoadPoint: {
                                position: { x: endPosition[0], y: endPosition[1], z: endPosition[2], },
                                rotation: { x: 0, y: endRotation[1], z: 0, },
                            },
                        },
                    },
                })

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

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

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

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

    return (
        startPosition.length > 0 && endPosition.length > 0 ? (
            <mesh>
                <primitive
                    name="start"
                    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);
                    }}
                />

                <primitive
                    name="end"
                    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);
                    }}
                />
            </mesh>
        ) : null
    );
}
export default VehicleUI;


