import { useFrame, useThree } from '@react-three/fiber';
import React, { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import * as Types from '../../../types/world/worldTypes';
import { QuadraticBezierLine } from '@react-three/drei';
import { useIsConnecting, useRenderDistance, useSimulationStates, useSocketStore } from '../../../store/store';
import useModuleStore from '../../../store/useModuleStore';
import { usePlayButtonStore } from '../../../store/usePlayButtonStore';
import { setEventApi } from '../../../services/factoryBuilder/assest/floorAsset/setEventsApt';

function PathConnector({ pathsGroupRef }: { pathsGroupRef: React.MutableRefObject<THREE.Group> }) {
    const { activeModule } = useModuleStore();
    const { gl, raycaster, scene, pointer, camera } = useThree();
    const { renderDistance } = useRenderDistance();
    const { setIsConnecting } = useIsConnecting();
    const { simulationStates, setSimulationStates } = useSimulationStates();
    const { isPlaying } = usePlayButtonStore();
    const { socket } = useSocketStore();
    const groupRefs = useRef<{ [key: string]: any }>({});

    const [firstSelected, setFirstSelected] = useState<{ modelUUID: string; sphereUUID: string; position: THREE.Vector3; isCorner: boolean; } | null>(null);
    const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3, end: THREE.Vector3, mid: THREE.Vector3 } | null>(null);
    const [helperlineColor, setHelperLineColor] = useState<string>('red');

    const updatePathConnections = (fromModelUUID: string, fromPointUUID: string, toModelUUID: string, toPointUUID: string) => {
        const updatedPaths = simulationStates.map(path => {
            if (path.type === 'Conveyor') {
                // Handle outgoing connections from Conveyor
                if (path.modeluuid === fromModelUUID) {
                    return {
                        ...path,
                        points: path.points.map(point => {
                            if (point.uuid === fromPointUUID) {
                                const newTarget = {
                                    modelUUID: toModelUUID,
                                    pointUUID: toPointUUID
                                };
                                const existingTargets = point.connections.targets || [];

                                if (!existingTargets.some(target =>
                                    target.modelUUID === newTarget.modelUUID &&
                                    target.pointUUID === newTarget.pointUUID
                                )) {
                                    return {
                                        ...point,
                                        connections: {
                                            ...point.connections,
                                            targets: [...existingTargets, newTarget]
                                        }
                                    };
                                }
                            }
                            return point;
                        })
                    };
                }
                // Handle incoming connections to Conveyor
                else if (path.modeluuid === toModelUUID) {
                    return {
                        ...path,
                        points: path.points.map(point => {
                            if (point.uuid === toPointUUID) {
                                const reverseTarget = {
                                    modelUUID: fromModelUUID,
                                    pointUUID: fromPointUUID
                                };
                                const existingTargets = point.connections.targets || [];

                                if (!existingTargets.some(target =>
                                    target.modelUUID === reverseTarget.modelUUID &&
                                    target.pointUUID === reverseTarget.pointUUID
                                )) {
                                    return {
                                        ...point,
                                        connections: {
                                            ...point.connections,
                                            targets: [...existingTargets, reverseTarget]
                                        }
                                    };
                                }
                            }
                            return point;
                        })
                    };
                }
            }
            else if (path.type === 'Vehicle') {
                // Handle outgoing connections from Vehicle
                if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
                    const newTarget = {
                        modelUUID: toModelUUID,
                        pointUUID: toPointUUID
                    };
                    const existingTargets = path.points.connections.targets || [];

                    // Check if target is a Conveyor
                    const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
                    if (toPath?.type !== 'Conveyor') {
                        console.log("Vehicle can only connect to Conveyors");
                        return path;
                    }

                    // Check if already has a connection
                    if (existingTargets.length >= 1) {
                        console.log("Vehicle can have only one connection");
                        return path;
                    }

                    if (!existingTargets.some(target =>
                        target.modelUUID === newTarget.modelUUID &&
                        target.pointUUID === newTarget.pointUUID
                    )) {
                        return {
                            ...path,
                            points: {
                                ...path.points,
                                connections: {
                                    ...path.points.connections,
                                    targets: [...existingTargets, newTarget]
                                }
                            }
                        };
                    }
                }
                // Handle incoming connections to Vehicle
                else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
                    const reverseTarget = {
                        modelUUID: fromModelUUID,
                        pointUUID: fromPointUUID
                    };
                    const existingTargets = path.points.connections.targets || [];

                    // Check if source is a Conveyor
                    const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
                    if (fromPath?.type !== 'Conveyor') {
                        console.log("Vehicle can only connect to Conveyors");
                        return path;
                    }

                    // Check if already has a connection
                    if (existingTargets.length >= 1) {
                        console.log("Vehicle can have only one connection");
                        return path;
                    }

                    if (!existingTargets.some(target =>
                        target.modelUUID === reverseTarget.modelUUID &&
                        target.pointUUID === reverseTarget.pointUUID
                    )) {
                        return {
                            ...path,
                            points: {
                                ...path.points,
                                connections: {
                                    ...path.points.connections,
                                    targets: [...existingTargets, reverseTarget]
                                }
                            }
                        };
                    }
                }
                return path;
            }
            else if (path.type === 'StaticMachine') {
                // Handle outgoing connections from StaticMachine
                if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
                    const newTarget = {
                        modelUUID: toModelUUID,
                        pointUUID: toPointUUID
                    };

                    // Ensure target is an ArmBot
                    const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
                    if (toPath?.type !== 'ArmBot') {
                        console.log("StaticMachine can only connect to ArmBot");
                        return path;
                    }

                    const existingTargets = path.points.connections.targets || [];

                    // Allow only one connection
                    if (existingTargets.length >= 1) {
                        console.log("StaticMachine can only have one connection");
                        return path;
                    }

                    if (!existingTargets.some(target =>
                        target.modelUUID === newTarget.modelUUID &&
                        target.pointUUID === newTarget.pointUUID
                    )) {
                        return {
                            ...path,
                            points: {
                                ...path.points,
                                connections: {
                                    ...path.points.connections,
                                    targets: [...existingTargets, newTarget]
                                }
                            }
                        };
                    }
                }

                // Handle incoming connections to StaticMachine
                else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
                    const reverseTarget = {
                        modelUUID: fromModelUUID,
                        pointUUID: fromPointUUID
                    };

                    const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
                    if (fromPath?.type !== 'ArmBot') {
                        console.log("StaticMachine can only be connected from ArmBot");
                        return path;
                    }

                    const existingTargets = path.points.connections.targets || [];

                    if (existingTargets.length >= 1) {
                        console.log("StaticMachine can only have one connection");
                        return path;
                    }

                    if (!existingTargets.some(target =>
                        target.modelUUID === reverseTarget.modelUUID &&
                        target.pointUUID === reverseTarget.pointUUID
                    )) {
                        return {
                            ...path,
                            points: {
                                ...path.points,
                                connections: {
                                    ...path.points.connections,
                                    targets: [...existingTargets, reverseTarget]
                                }
                            }
                        };
                    }
                }
                return path;
            }
            else if (path.type === 'ArmBot') {
                // Handle outgoing connections from ArmBot
                if (path.modeluuid === fromModelUUID && path.points.uuid === fromPointUUID) {
                    const newTarget = {
                        modelUUID: toModelUUID,
                        pointUUID: toPointUUID
                    };

                    const toPath = simulationStates.find(p => p.modeluuid === toModelUUID);
                    if (!toPath) return path;

                    const existingTargets = path.points.connections.targets || [];

                    // Check if connecting to a StaticMachine and already connected to one
                    const alreadyConnectedToStatic = existingTargets.some(target => {
                        const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
                        return targetPath?.type === 'StaticMachine';
                    });

                    if (toPath.type === 'StaticMachine') {
                        if (alreadyConnectedToStatic) {
                            console.log("ArmBot can only connect to one StaticMachine");
                            return path;
                        }
                    }

                    if (!existingTargets.some(target =>
                        target.modelUUID === newTarget.modelUUID &&
                        target.pointUUID === newTarget.pointUUID
                    )) {
                        return {
                            ...path,
                            points: {
                                ...path.points,
                                connections: {
                                    ...path.points.connections,
                                    targets: [...existingTargets, newTarget]
                                }
                            }
                        };
                    }
                }

                // Handle incoming connections to ArmBot
                else if (path.modeluuid === toModelUUID && path.points.uuid === toPointUUID) {
                    const reverseTarget = {
                        modelUUID: fromModelUUID,
                        pointUUID: fromPointUUID
                    };

                    const fromPath = simulationStates.find(p => p.modeluuid === fromModelUUID);
                    if (!fromPath) return path;

                    const existingTargets = path.points.connections.targets || [];

                    const alreadyConnectedFromStatic = existingTargets.some(target => {
                        const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
                        return targetPath?.type === 'StaticMachine';
                    });

                    if (fromPath.type === 'StaticMachine') {
                        if (alreadyConnectedFromStatic) {
                            console.log("ArmBot can only be connected from one StaticMachine");
                            return path;
                        }
                    }

                    if (!existingTargets.some(target =>
                        target.modelUUID === reverseTarget.modelUUID &&
                        target.pointUUID === reverseTarget.pointUUID
                    )) {
                        return {
                            ...path,
                            points: {
                                ...path.points,
                                connections: {
                                    ...path.points.connections,
                                    targets: [...existingTargets, reverseTarget]
                                }
                            }
                        };
                    }
                }
                return path;
            }

            return path;
        });

        setSimulationStates(updatedPaths);

        const updatedPathDetails = updatedPaths.filter(path =>
            path.modeluuid === fromModelUUID || path.modeluuid === toModelUUID
        );

        // updateBackend(updatedPathDetails);
    };

    const updateBackend = async (updatedPaths: (Types.ConveyorEventsSchema | Types.VehicleEventsSchema | Types.StaticMachineEventsSchema | Types.ArmBotEventsSchema)[]) => {
        if (updatedPaths.length === 0) return;
        const email = localStorage.getItem("email");
        const organization = email ? email.split("@")[1].split(".")[0] : "";

        updatedPaths.forEach(async (updatedPath) => {
            if (updatedPath.type === 'Conveyor') {

                // await setEventApi(
                //   organization,
                //   updatedPath.modeluuid,
                //   { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
                // );

                const data = {
                    organization: organization,
                    modeluuid: updatedPath.modeluuid,
                    eventData: { type: "Conveyor", points: updatedPath.points, speed: updatedPath.speed }
                }

                socket.emit('v2:model-asset:updateEventData', data);

            } else if (updatedPath.type === 'Vehicle') {

                // await setEventApi(
                //     organization,
                //     updatedPath.modeluuid,
                //     { type: "Vehicle", points: updatedPath.points }
                // );

                const data = {
                    organization: organization,
                    modeluuid: updatedPath.modeluuid,
                    eventData: { type: "Vehicle", points: updatedPath.points }
                }

                socket.emit('v2:model-asset:updateEventData', data);

            }
        })

    }

    const handleAddConnection = (fromModelUUID: string, fromUUID: string, toModelUUID: string, toUUID: string) => {
        updatePathConnections(fromModelUUID, fromUUID, toModelUUID, toUUID);
        setFirstSelected(null);
        setCurrentLine(null);
        setIsConnecting(false);
    };

    useEffect(() => {
        const canvasElement = gl.domElement;
        let drag = false;
        let MouseDown = false;

        const onMouseDown = () => {
            MouseDown = true;
            drag = false;
        };

        const onMouseUp = () => {
            MouseDown = false;
        };

        const onMouseMove = () => {
            if (MouseDown) {
                drag = true;
            }
        };

        const onContextMenu = (evt: MouseEvent) => {
            evt.preventDefault();
            if (drag || evt.button === 0) return;

            raycaster.setFromCamera(pointer, camera);
            const intersects = raycaster.intersectObjects(pathsGroupRef.current.children, true);

            if (intersects.length > 0) {
                const intersected = intersects[0].object;

                if (intersected.name.includes("events-sphere")) {
                    const modelUUID = intersected.userData.path.modeluuid;
                    const sphereUUID = intersected.uuid;
                    const worldPosition = new THREE.Vector3();
                    intersected.getWorldPosition(worldPosition);

                    let isStartOrEnd = false;

                    if (intersected.userData.path.points && intersected.userData.path.points.length > 1) {
                        isStartOrEnd = intersected.userData.path.points.length > 0 && (
                            sphereUUID === intersected.userData.path.points[0].uuid ||
                            sphereUUID === intersected.userData.path.points[intersected.userData.path.points.length - 1].uuid
                        );
                    } else if (intersected.userData.path.points) {
                        isStartOrEnd = sphereUUID === intersected.userData.path.points.uuid;
                    }

                    if (modelUUID) {
                        const firstPath = simulationStates.find(p => p.modeluuid === firstSelected?.modelUUID);
                        const secondPath = simulationStates.find(p => p.modeluuid === modelUUID);

                        // Prevent vehicle-to-vehicle connections
                        if (firstPath && secondPath && firstPath.type === 'Vehicle' && secondPath.type === 'Vehicle') {
                            console.log("Cannot connect two vehicle paths together");
                            return;
                        }

                        // Prevent conveyor middle point to conveyor connections
                        if (firstPath && secondPath &&
                            firstPath.type === 'Conveyor' &&
                            secondPath.type === 'Conveyor' &&
                            (!firstSelected?.isCorner || !isStartOrEnd)) {
                            console.log("Conveyor connections must be between start/end points");
                            return;
                        }

                        // Check if this specific connection already exists
                        const isDuplicateConnection = firstSelected
                            ? simulationStates.some(path => {
                                if (path.modeluuid === firstSelected.modelUUID) {
                                    if (path.type === 'Conveyor') {
                                        const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
                                        return point?.connections.targets.some(t =>
                                            t.modelUUID === modelUUID && t.pointUUID === sphereUUID
                                        );
                                    } else if (path.type === 'Vehicle') {
                                        return path.points.connections.targets.some(t =>
                                            t.modelUUID === modelUUID && t.pointUUID === sphereUUID
                                        );
                                    }
                                }
                                return false;
                            })
                            : false;

                        if (isDuplicateConnection) {
                            console.log("These points are already connected. Ignoring.");
                            return;
                        }

                        // For Vehicles, check if they're already connected to anything
                        if (intersected.userData.path.type === 'Vehicle') {
                            console.log('intersected: ', intersected);
                            const vehicleConnections = intersected.userData.path.points.connections.targets.length;
                            if (vehicleConnections >= 1) {
                                console.log("Vehicle can only have one connection");
                                return;
                            }
                        }

                        // For non-Vehicle paths, check if already connected
                        if (intersected.userData.path.type !== 'Vehicle') {
                            const isAlreadyConnected = simulationStates.some(path => {
                                if (path.type === 'Conveyor') {
                                    return path.points.some(point =>
                                        point.uuid === sphereUUID &&
                                        point.connections.targets.length > 0
                                    );
                                }
                                return false;
                            });

                            if (isAlreadyConnected) {
                                console.log("Conveyor point is already connected. Ignoring.");
                                return;
                            }
                        }

                        if (firstSelected) {
                            // Check if trying to connect Vehicle to non-Conveyor
                            if ((firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
                                (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor')) {
                                console.log("Vehicle can only connect to Conveyors");
                                return;
                            }

                            // Prevent same-path connections
                            if (firstSelected.modelUUID === modelUUID) {
                                console.log("Cannot connect spheres on the same path.");
                                return;
                            }

                            // Check if StaticMachine is involved in the connection
                            if ((firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') ||
                                (secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot')) {
                                console.log("StaticMachine can only connect to ArmBot");
                                return;
                            }

                            // Check if StaticMachine already has a connection
                            if (firstPath?.type === 'StaticMachine') {
                                const staticConnections = firstPath.points.connections.targets.length;
                                if (staticConnections >= 1) {
                                    console.log("StaticMachine can only have one connection");
                                    return;
                                }
                            }
                            if (secondPath?.type === 'StaticMachine') {
                                const staticConnections = secondPath.points.connections.targets.length;
                                if (staticConnections >= 1) {
                                    console.log("StaticMachine can only have one connection");
                                    return;
                                }
                            }

                            // Check if ArmBot is involved
                            if ((firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') ||
                                (secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine')) {

                                const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath;
                                const staticPath = firstPath?.type === 'StaticMachine' ? firstPath : secondPath;

                                const armBotConnections = armBotPath.points.connections.targets || [];
                                const alreadyConnectedToStatic = armBotConnections.some(target => {
                                    const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
                                    return targetPath?.type === 'StaticMachine';
                                });

                                if (alreadyConnectedToStatic) {
                                    console.log("ArmBot can only connect to one StaticMachine");
                                    return;
                                }

                                const staticConnections = staticPath.points.connections.targets.length;
                                if (staticConnections >= 1) {
                                    console.log("StaticMachine can only have one connection");
                                    return;
                                }
                            }

                            // Prevent ArmBot ↔ ArmBot
                            if (firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot') {
                                console.log("Cannot connect two ArmBots together");
                                return;
                            }

                            // If one is ArmBot, ensure the other is StaticMachine or Conveyor
                            if (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') {
                                const otherType = firstPath?.type === 'ArmBot' ? secondPath?.type : firstPath?.type;
                                if (otherType !== 'StaticMachine' && otherType !== 'Conveyor') {
                                    console.log("ArmBot can only connect to Conveyors or one StaticMachine");
                                    return;
                                }
                            }

                            // At least one must be start/end point
                            if (!firstSelected.isCorner && !isStartOrEnd) {
                                console.log("At least one of the selected spheres must be a start or end point.");
                                return;
                            }

                            // All checks passed - make the connection
                            handleAddConnection(
                                firstSelected.modelUUID,
                                firstSelected.sphereUUID,
                                modelUUID,
                                sphereUUID
                            );
                        } else {
                            // First selection - just store it
                            setFirstSelected({
                                modelUUID,
                                sphereUUID,
                                position: worldPosition,
                                isCorner: isStartOrEnd
                            });
                            setIsConnecting(true);
                        }
                    }
                }
            } else {
                // Clicked outside - cancel connection
                setFirstSelected(null);
                setCurrentLine(null);
                setIsConnecting(false);
            }
        };

        if (activeModule === 'simulation') {
            canvasElement.addEventListener("mousedown", onMouseDown);
            canvasElement.addEventListener("mouseup", onMouseUp);
            canvasElement.addEventListener("mousemove", onMouseMove);
            canvasElement.addEventListener("contextmenu", onContextMenu);
        } else {
            setFirstSelected(null);
            setCurrentLine(null);
            setIsConnecting(false);
        }

        return () => {
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
            canvasElement.removeEventListener("contextmenu", onContextMenu);
        };
    }, [camera, scene, raycaster, firstSelected, simulationStates]);

    useFrame(() => {
        Object.values(groupRefs.current).forEach((group) => {
            if (group) {
                const distance = new THREE.Vector3(...group.position.toArray()).distanceTo(camera.position);
                group.visible = ((distance <= renderDistance) && !isPlaying);
            }
        });
    });

    useFrame(() => {
        if (firstSelected) {
            raycaster.setFromCamera(pointer, camera);
            const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) =>
                !intersect.object.name.includes("Roof") &&
                !intersect.object.name.includes("agv-collider") &&
                !intersect.object.name.includes("MeasurementReference") &&
                !intersect.object.userData.isPathObject &&
                !(intersect.object.type === "GridHelper")
            );

            let point: THREE.Vector3 | null = null;
            let snappedSphere: { sphereUUID: string, position: THREE.Vector3, modelUUID: string, isCorner: boolean } | null = null;
            let isInvalidConnection = false;

            if (intersects.length > 0) {
                point = intersects[0].point;
                if (point.y < 0.05) {
                    point = new THREE.Vector3(point.x, 0.05, point.z);
                }
            }

            const sphereIntersects = raycaster.intersectObjects(pathsGroupRef.current.children, true).filter((obj) =>
                obj.object.name.includes("events-sphere")
            );

            if (sphereIntersects.length > 0) {
                const sphere = sphereIntersects[0].object;
                const sphereUUID = sphere.uuid;
                const spherePosition = new THREE.Vector3();
                sphere.getWorldPosition(spherePosition);
                const pathData = sphere.userData.path;
                const modelUUID = pathData.modeluuid;

                const firstPath = simulationStates.find(p => p.modeluuid === firstSelected.modelUUID);
                const secondPath = simulationStates.find(p => p.modeluuid === modelUUID);
                const isVehicleToVehicle = firstPath?.type === 'Vehicle' && secondPath?.type === 'Vehicle';

                // Inside the useFrame hook, where we check for snapped spheres:
                const isConnectable = (pathData.type === 'Vehicle' ||
                    (pathData.points.length > 0 && (
                        sphereUUID === pathData.points[0].uuid ||
                        sphereUUID === pathData.points[pathData.points.length - 1].uuid
                    ))) &&
                    !isVehicleToVehicle &&
                    !(firstPath?.type === 'Conveyor' &&
                        pathData.type === 'Conveyor' &&
                        !firstSelected.isCorner);

                // Check for duplicate connection (regardless of path type)
                const isDuplicateConnection = simulationStates.some(path => {
                    if (path.modeluuid === firstSelected.modelUUID) {
                        if (path.type === 'Conveyor') {
                            const point = path.points.find(p => p.uuid === firstSelected.sphereUUID);
                            return point?.connections.targets.some(t =>
                                t.modelUUID === modelUUID && t.pointUUID === sphereUUID
                            );
                        } else if (path.type === 'Vehicle') {
                            return path.points.connections.targets.some(t =>
                                t.modelUUID === modelUUID && t.pointUUID === sphereUUID
                            );
                        }
                    }
                    return false;
                });

                // For non-Vehicle paths, check if already connected
                const isNonVehicleAlreadyConnected = pathData.type !== 'Vehicle' &&
                    simulationStates.some(path => {
                        if (path.type === 'Conveyor') {
                            return path.points.some(point =>
                                point.uuid === sphereUUID &&
                                point.connections.targets.length > 0
                            );
                        }
                        return false;
                    });

                // Check vehicle connection rules
                const isVehicleAtMaxConnections = pathData.type === 'Vehicle' &&
                    pathData.points.connections.targets.length >= 1;
                const isVehicleConnectingToNonConveyor =
                    (firstPath?.type === 'Vehicle' && secondPath?.type !== 'Conveyor') ||
                    (secondPath?.type === 'Vehicle' && firstPath?.type !== 'Conveyor');

                // Check if StaticMachine is connecting to non-ArmBot
                const isStaticMachineToNonArmBot =
                    (firstPath?.type === 'StaticMachine' && secondPath?.type !== 'ArmBot') ||
                    (secondPath?.type === 'StaticMachine' && firstPath?.type !== 'ArmBot');

                // Check if StaticMachine already has a connection
                const isStaticMachineAtMaxConnections =
                    (firstPath?.type === 'StaticMachine' && firstPath.points.connections.targets.length >= 1) ||
                    (secondPath?.type === 'StaticMachine' && secondPath.points.connections.targets.length >= 1);

                // Check if ArmBot is connecting to StaticMachine
                const isArmBotToStaticMachine =
                    (firstPath?.type === 'ArmBot' && secondPath?.type === 'StaticMachine') ||
                    (secondPath?.type === 'ArmBot' && firstPath?.type === 'StaticMachine');

                // Prevent multiple StaticMachine connections to ArmBot
                let isArmBotAlreadyConnectedToStatic = false;
                if (isArmBotToStaticMachine) {
                    const armBotPath = firstPath?.type === 'ArmBot' ? firstPath : secondPath;
                    isArmBotAlreadyConnectedToStatic = armBotPath.points.connections.targets.some(target => {
                        const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
                        return targetPath?.type === 'StaticMachine';
                    });
                }

                // Prevent ArmBot to ArmBot
                const isArmBotToArmBot = firstPath?.type === 'ArmBot' && secondPath?.type === 'ArmBot';

                // If ArmBot is involved, other must be Conveyor or StaticMachine
                const isArmBotToInvalidType = (firstPath?.type === 'ArmBot' || secondPath?.type === 'ArmBot') &&
                    !(firstPath?.type === 'Conveyor' || firstPath?.type === 'StaticMachine' ||
                        secondPath?.type === 'Conveyor' || secondPath?.type === 'StaticMachine');

                if (
                    !isDuplicateConnection &&
                    !isVehicleToVehicle &&
                    !isNonVehicleAlreadyConnected &&
                    !isVehicleAtMaxConnections &&
                    !isVehicleConnectingToNonConveyor &&
                    !isStaticMachineToNonArmBot &&
                    !isStaticMachineAtMaxConnections &&
                    !isArmBotToArmBot &&
                    !isArmBotToInvalidType &&
                    !isArmBotAlreadyConnectedToStatic &&
                    firstSelected.sphereUUID !== sphereUUID &&
                    firstSelected.modelUUID !== modelUUID &&
                    (firstSelected.isCorner || isConnectable) &&
                    !(firstPath?.type === 'Conveyor' &&
                        pathData.type === 'Conveyor' &&
                        !(firstSelected.isCorner && isConnectable))
                ) {
                    snappedSphere = {
                        sphereUUID,
                        position: spherePosition,
                        modelUUID,
                        isCorner: isConnectable
                    };
                } else {
                    isInvalidConnection = true;
                }

            }

            if (snappedSphere) {
                point = snappedSphere.position;
            }

            if (point) {
                const distance = firstSelected.position.distanceTo(point);
                const heightFactor = Math.max(0.5, distance * 0.2);
                const midPoint = new THREE.Vector3(
                    (firstSelected.position.x + point.x) / 2,
                    Math.max(firstSelected.position.y, point.y) + heightFactor,
                    (firstSelected.position.z + point.z) / 2
                );

                setCurrentLine({
                    start: firstSelected.position,
                    end: point,
                    mid: midPoint,
                });

                if (sphereIntersects.length > 0) {
                    setHelperLineColor(isInvalidConnection ? 'red' : '#6cf542');
                } else {
                    setHelperLineColor('yellow');
                }
            } else {
                setCurrentLine(null);
                setIsConnecting(false);
            }
        } else {
            setCurrentLine(null);
            setIsConnecting(false);
        }
    });

    return (
        <group name='simulationConnectionGroup' visible={!isPlaying}>
            {simulationStates.flatMap(path => {
                if (path.type === 'Conveyor') {
                    return path.points.flatMap(point =>
                        point.connections.targets.map((target, index) => {
                            const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
                            if (targetPath?.type === 'Vehicle') return null;

                            const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', point.uuid);
                            const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);

                            if (fromSphere && toSphere) {
                                const fromWorldPosition = new THREE.Vector3();
                                const toWorldPosition = new THREE.Vector3();
                                fromSphere.getWorldPosition(fromWorldPosition);
                                toSphere.getWorldPosition(toWorldPosition);

                                const distance = fromWorldPosition.distanceTo(toWorldPosition);
                                const heightFactor = Math.max(0.5, distance * 0.2);
                                const midPoint = new THREE.Vector3(
                                    (fromWorldPosition.x + toWorldPosition.x) / 2,
                                    Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
                                    (fromWorldPosition.z + toWorldPosition.z) / 2
                                );

                                return (
                                    <QuadraticBezierLine
                                        key={`${point.uuid}-${target.pointUUID}-${index}`}
                                        ref={(el) => (groupRefs.current[`${point.uuid}-${target.pointUUID}-${index}`] = el!)}
                                        start={fromWorldPosition.toArray()}
                                        end={toWorldPosition.toArray()}
                                        mid={midPoint.toArray()}
                                        color="white"
                                        lineWidth={4}
                                        dashed
                                        dashSize={0.75}
                                        dashScale={20}
                                    />
                                );
                            }
                            return null;
                        })
                    );
                }

                if (path.type === 'Vehicle') {
                    return path.points.connections.targets.map((target, index) => {
                        const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
                        const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);

                        if (fromSphere && toSphere) {
                            const fromWorldPosition = new THREE.Vector3();
                            const toWorldPosition = new THREE.Vector3();
                            fromSphere.getWorldPosition(fromWorldPosition);
                            toSphere.getWorldPosition(toWorldPosition);

                            const distance = fromWorldPosition.distanceTo(toWorldPosition);
                            const heightFactor = Math.max(0.5, distance * 0.2);
                            const midPoint = new THREE.Vector3(
                                (fromWorldPosition.x + toWorldPosition.x) / 2,
                                Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
                                (fromWorldPosition.z + toWorldPosition.z) / 2
                            );

                            return (
                                <QuadraticBezierLine
                                    key={`${path.points.uuid}-${target.pointUUID}-${index}`}
                                    ref={(el) => (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)}
                                    start={fromWorldPosition.toArray()}
                                    end={toWorldPosition.toArray()}
                                    mid={midPoint.toArray()}
                                    color="orange"
                                    lineWidth={4}
                                    dashed
                                    dashSize={0.75}
                                    dashScale={20}
                                />
                            );
                        }
                        return null;
                    });
                }

                if (path.type === 'StaticMachine') {
                    return path.points.connections.targets.map((target, index) => {
                        const targetPath = simulationStates.find(p => p.modeluuid === target.modelUUID);
                        if (targetPath?.type !== 'ArmBot') return null;

                        const fromSphere = pathsGroupRef.current?.getObjectByProperty('uuid', path.points.uuid);
                        const toSphere = pathsGroupRef.current?.getObjectByProperty('uuid', target.pointUUID);

                        if (fromSphere && toSphere) {
                            const fromWorldPosition = new THREE.Vector3();
                            const toWorldPosition = new THREE.Vector3();
                            fromSphere.getWorldPosition(fromWorldPosition);
                            toSphere.getWorldPosition(toWorldPosition);

                            const distance = fromWorldPosition.distanceTo(toWorldPosition);
                            const heightFactor = Math.max(0.5, distance * 0.2);
                            const midPoint = new THREE.Vector3(
                                (fromWorldPosition.x + toWorldPosition.x) / 2,
                                Math.max(fromWorldPosition.y, toWorldPosition.y) + heightFactor,
                                (fromWorldPosition.z + toWorldPosition.z) / 2
                            );

                            return (
                                <QuadraticBezierLine
                                    key={`${path.points.uuid}-${target.pointUUID}-${index}`}
                                    ref={(el) => (groupRefs.current[`${path.points.uuid}-${target.pointUUID}-${index}`] = el!)}
                                    start={fromWorldPosition.toArray()}
                                    end={toWorldPosition.toArray()}
                                    mid={midPoint.toArray()}
                                    color="#42a5f5"
                                    lineWidth={4}
                                    dashed
                                    dashSize={0.75}
                                    dashScale={20}
                                />
                            );
                        }
                        return null;
                    });
                }

                return [];
            })}

            {currentLine && (
                <QuadraticBezierLine
                    start={currentLine.start.toArray()}
                    end={currentLine.end.toArray()}
                    mid={currentLine.mid.toArray()}
                    color={helperlineColor}
                    lineWidth={4}
                    dashed
                    dashSize={1}
                    dashScale={20}
                />
            )}
        </group>
    );

}

export default PathConnector;