import { useEffect, useRef, useState } from 'react'
import { useGLTF } from '@react-three/drei';
import { useFrame, useThree } from '@react-three/fiber';
import { useIsDragging, useIsRotating, useSelectedAction, useSelectedEventSphere } from '../../../../../store/simulation/useSimulationStore';
import { useProductContext } from '../../../products/productContext';
import { useSceneContext } from '../../../../scene/sceneContext';
import { Group, Plane, Vector3 } from 'three';
import { useVersionContext } from '../../../../builder/version/versionContext';
import { useParams } from 'react-router-dom';
import startPoint from "../../../../../assets/gltf-glb/ui/arrow_green.glb";
import startEnd from "../../../../../assets/gltf-glb/ui/arrow_red.glb";
import { upsertProductOrEventApi } from '../../../../../services/simulation/products/UpsertProductOrEventApi';

function HumanUi() {
    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 outerGroup = useRef<Group>(null);
    const prevMousePos = useRef({ x: 0, y: 0 });
    const { controls, raycaster } = useThree();
    const { selectedEventSphere } = useSelectedEventSphere();
    const { selectedProductStore } = useProductContext();
    const { humanStore, productStore } = useSceneContext();
    const { selectedProduct } = selectedProductStore();
    const { humans, getHumanById } = humanStore();
    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 { isDragging, setIsDragging } = useIsDragging();
    const { isRotating, setIsRotating } = useIsRotating();
    const plane = useRef(new Plane(new Vector3(0, 1, 0), 0));

    const [selectedHumanData, setSelectedHumanData] = useState<{
        position: [number, number, number];
        rotation: [number, number, number];
    }>({ position: [0, 0, 0], rotation: [0, 0, 0] });

    const { selectedAction } = useSelectedAction();
    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 selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);

        if (selectedHuman) {
            setSelectedHumanData({
                position: selectedHuman.position,
                rotation: selectedHuman.rotation,
            });

            if (selectedHuman.point?.actions && selectedAction.actionId) {
                const action = selectedHuman.point.actions.find(a => a.actionUuid === selectedAction.actionId);

                if (action?.animationSequences[0]) {
                    const sequence = action.animationSequences[0];

                    if (sequence.startPoint?.position && outerGroup.current) {
                        const worldPos = new Vector3(...sequence.startPoint.position);
                        const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
                        setStartPosition([localPosition.x, 0.5, localPosition.z]);
                        setStartRotation(sequence.startPoint.rotation || [0, 0, 0]);
                    }

                    if (sequence.endPoint?.position && outerGroup.current) {
                        const worldPos = new Vector3(...sequence.endPoint.position);
                        const localPosition = outerGroup.current.worldToLocal(worldPos.clone());
                        setEndPosition([localPosition.x, 0.5, localPosition.z]);
                        setEndRotation(sequence.endPoint.rotation || [0, 0, 0]);
                    }
                }
            }
        }
    }, [selectedEventSphere, outerGroup.current, selectedAction, humans]);

    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 as any).enabled = false;
            setIsDragging(null);
        } else {
            setIsDragging(state);
            setIsRotating(null);
            if (controls) (controls as any).enabled = false;
        }
    };

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

        if (selectedEventSphere?.userData.modelUuid && selectedAction.actionId) {
            const selectedHuman = getHumanById(selectedEventSphere.userData.modelUuid);

            if (selectedHuman && outerGroup.current && startMarker.current && endMarker.current) {
                const worldPosStart = new Vector3(...startPosition);
                const globalStartPosition = outerGroup.current.localToWorld(worldPosStart.clone());

                const worldPosEnd = new Vector3(...endPosition);
                const globalEndPosition = outerGroup.current.localToWorld(worldPosEnd.clone());

                const updatedActions = selectedHuman.point.actions.map(action => {
                    if (action.actionUuid === selectedAction.actionId) {
                        const updatedSequences = action.animationSequences.map(sequence => {
                            return {
                                ...sequence,
                                startPoint: {
                                    position: [globalStartPosition.x, globalStartPosition.y, globalStartPosition.z] as [number, number, number],
                                    rotation: startRotation
                                },
                                endPoint: {
                                    position: [globalEndPosition.x, globalEndPosition.y, globalEndPosition.z] as [number, number, number],
                                    rotation: endRotation
                                }
                            };
                        });

                        return {
                            ...action,
                            animationSequences: updatedSequences
                        };
                    }
                    return action;
                });

                const event = updateEvent(
                    selectedProduct.productUuid,
                    selectedEventSphere.userData.modelUuid,
                    {
                        ...selectedHuman,
                        point: {
                            ...selectedHuman.point,
                            actions: updatedActions
                        }
                    }
                );

                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, 0.5, localPoint.z]);
        } else if (isDragging === "end") {
            setEndPosition([localPoint.x, 0.5, localPoint.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;
            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,
                ]);
            }
        }
    });

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

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

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

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

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

export default HumanUi