import React, { useEffect, useState } from 'react';
import { useSelectedAction, useSelectedEventSphere, useSelectedProduct } from '../../../../store/simulation/useSimulationStore';
import { useGLTF } from '@react-three/drei';
import { useThree } from '@react-three/fiber';
import { useProductStore } from '../../../../store/simulation/useProductStore';
import { useArmBotStore } from '../../../../store/simulation/useArmBotStore';
import PickDropPoints from './PickDropPoints';
import useDraggableGLTF from './useDraggableGLTF';
import * as THREE from 'three';

import armPick from "../../../../assets/gltf-glb/ui/arm_ui_pick.glb";
import armDrop from "../../../../assets/gltf-glb/ui/arm_ui_drop.glb";
import { upsertProductOrEventApi } from '../../../../services/simulation/UpsertProductOrEventApi';

type Positions = {
    pick: [number, number, number];
    drop: [number, number, number];
    default: [number, number, number];
};

const ArmBotUI = () => {
    const { getEventByModelUuid, updateAction, getActionByUuid } = useProductStore();
    const { selectedEventSphere } = useSelectedEventSphere();
    const { selectedProduct } = useSelectedProduct();
    const { scene } = useThree();
    const { selectedAction } = useSelectedAction();
    const { armBots } = useArmBotStore();

    const armUiPick = useGLTF(armPick) as any;
    const armUiDrop = useGLTF(armDrop) as any;

    const [startPosition, setStartPosition] = useState<[number, number, number] | null>([0, 0, 0]);
    const [endPosition, setEndPosition] = useState<[number, number, number] | null>([0, 0, 0]);
    const [selectedArmBotData, setSelectedArmBotData] = useState<any>(null);

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

    // Fetch and setup selected ArmBot data
    useEffect(() => {
        if (selectedEventSphere) {
            const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventSphere.userData.modelUuid);

            if (selectedArmBot?.type === "roboticArm" && selectedAction.actionId) {
                setSelectedArmBotData(selectedArmBot);
                const defaultPositions = getDefaultPositions(selectedArmBot.modelUuid);
                const matchingAction = getActionByUuid(selectedProduct.productId, selectedAction.actionId);
                if (matchingAction && (matchingAction as RoboticArmPointSchema["actions"][0]).process) {
                    const startPoint = (matchingAction as RoboticArmPointSchema["actions"][0]).process.startPoint;
                    const pickPosition = (!startPoint || (Array.isArray(startPoint) && startPoint.every(v => v === 0)))
                        ? defaultPositions.pick
                        : startPoint;

                    const endPoint = (matchingAction as RoboticArmPointSchema["actions"][0]).process.endPoint;
                    const dropPosition = (!endPoint || (Array.isArray(endPoint) && endPoint.every(v => v === 0)))
                        ? defaultPositions.drop
                        : endPoint;

                    setStartPosition(pickPosition);
                    setEndPosition(dropPosition);
                }
            }
        }
    }, [armBots, selectedEventSphere, selectedProduct, getEventByModelUuid, selectedAction]);

    function getDefaultPositions(modelUuid: string): Positions {
        const modelData = getEventByModelUuid(selectedProduct.productId, modelUuid);

        if (modelData?.type === "roboticArm") {
            const baseX = modelData.point.position?.[0] || 0;
            const baseY = modelData.point.position?.[1] || 0;;
            const baseZ = modelData.point.position?.[2] || 0;
            return {
                pick: [baseX, baseY, baseZ + 0.5],
                drop: [baseX, baseY, baseZ - 0.5],
                default: [baseX, baseY, baseZ],
            };
        }

        return {
            pick: [0.5, 1.5, 0],
            drop: [-0.5, 1.5, 0],
            default: [0, 1.5, 0],
        };
    }

    function getLocalPosition(parentUuid: string, worldPosArray: [number, number, number] | null): [number, number, number] | null {
        if (worldPosArray) {
            const worldPos = new THREE.Vector3(...worldPosArray);
            const parentObject = scene.getObjectByProperty('uuid', parentUuid);

            if (parentObject) {
                const localPos = worldPos.clone();
                parentObject.worldToLocal(localPos);
                return [localPos.x, localPos.y, localPos.z];
            }
        }
        return null;
    }

    const updatePointToState = (obj: THREE.Object3D) => {
        const { modelUuid, actionType, actionUuid } = obj.userData;
        const newPosition = new THREE.Vector3();
        obj.getWorldPosition(newPosition);
        const worldPositionArray = newPosition.toArray() as [number, number, number];

        if (selectedEventSphere) {
            const selectedArmBot = getEventByModelUuid(selectedProduct.productId, selectedEventSphere.userData.modelUuid);

            const armBot = selectedArmBot?.modelUuid === modelUuid ? selectedArmBot : null;
            if (!armBot) return;

            if (armBot.type === "roboticArm") {
                armBot?.point?.actions?.map((action) => {
                    if (action.actionUuid === actionUuid) {
                        const updatedProcess = { ...action.process };

                        if (actionType === "pick") {
                            updatedProcess.startPoint = getLocalPosition(modelUuid, worldPositionArray);
                            setStartPosition(updatedProcess.startPoint)

                        } else if (actionType === "drop") {
                            updatedProcess.endPoint = getLocalPosition(modelUuid, worldPositionArray);
                            setEndPosition(updatedProcess.endPoint)
                        }

                        const event = updateAction(selectedProduct.productId,
                            actionUuid,
                            {
                                actionUuid: action.actionUuid,
                                process: updatedProcess,
                            }
                        )

                        if (event) {
                            updateBackend(
                                selectedProduct.productName,
                                selectedProduct.productId,
                                organization,
                                event
                            );
                        }
                        return {
                            ...action,
                            process: updatedProcess,
                        };
                    }
                    return action;
                });

            }
        }
    }

    const { handlePointerDown } = useDraggableGLTF(updatePointToState);

    if (!selectedArmBotData || !Array.isArray(selectedArmBotData.point?.actions)) {
        return null; // avoid rendering if no data yet
    }
    return (
        <>
            {selectedArmBotData.point.actions.map((action: any) => {
                if (action.actionUuid === selectedAction.actionId) {
                    return (
                        <React.Fragment key={action.actionUuid}>
                            <group
                                position={new THREE.Vector3(...selectedArmBotData.position)}
                                rotation={new THREE.Euler(...selectedArmBotData.rotation)}
                            >
                                {startPosition && endPosition && (
                                    <>
                                        <PickDropPoints
                                            position={startPosition}
                                            modelUuid={selectedArmBotData.modelUuid}
                                            pointUuid={selectedArmBotData.point.uuid}
                                            actionType="pick"
                                            actionUuid={action.actionUuid}
                                            gltfScene={armUiPick.scene}
                                            handlePointerDown={handlePointerDown}
                                            isSelected={true}
                                        />
                                        <PickDropPoints
                                            position={endPosition}
                                            modelUuid={selectedArmBotData.modelUuid}
                                            pointUuid={selectedArmBotData.point.uuid}
                                            actionType="drop"
                                            actionUuid={action.actionUuid}
                                            gltfScene={armUiDrop.scene}
                                            handlePointerDown={handlePointerDown}
                                            isSelected={true}
                                        />
                                    </>
                                )}
                            </group>
                        </React.Fragment>
                    );
                } else {
                    return null; // important! must return something
                }
            })}
        </>
    );

};

export default ArmBotUI;
