import { useEffect, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber";
import * as THREE from "three";
import { useSubModuleStore } from "../../../../store/useModuleStore";
import { useSelectedAction, useSelectedAsset, useSelectedEventData } from "../../../../store/simulation/useSimulationStore";
import { handleAddEventToProduct } from "../points/functions/handleAddEventToProduct";
import { QuadraticBezierLine } from "@react-three/drei";
import { upsertProductOrEventApi } from "../../../../services/simulation/products/UpsertProductOrEventApi";
import { usePlayButtonStore } from "../../../../store/usePlayButtonStore";
import { ArrowOnQuadraticBezier, Arrows } from "../arrows/arrows";
import { useProductContext } from "../../products/productContext";
import { useParams } from "react-router-dom";
import { useToolMode } from "../../../../store/builder/store";
import { useVersionContext } from "../../../builder/version/versionContext";
import { useSceneContext } from "../../../scene/sceneContext";

interface ConnectionLine {
    id: string;
    startPointUuid: string;
    endPointUuid: string;
    trigger: TriggerSchema;
}

function TriggerConnector() {
    const { gl, raycaster, scene, pointer, camera } = useThree();
    const { subModule } = useSubModuleStore();
    const { selectedProductStore } = useProductContext();
    const { eventStore, productStore } = useSceneContext();
    const { products, getPointByUuid, getIsEventInProduct, getActionByUuid, addTrigger, removeTrigger, addEvent, getEventByModelUuid, getPointUuidByActionUuid, getProductById } = productStore();
    const { selectedAsset, clearSelectedAsset } = useSelectedAsset();
    const { selectedProduct } = selectedProductStore();
    const [hoveredLineKey, setHoveredLineKey] = useState<string | null>(null);
    const groupRefs = useRef<Record<string, any>>({});
    const [helperlineColor, setHelperLineColor] = useState<string>("red");
    const [currentLine, setCurrentLine] = useState<{ start: THREE.Vector3; end: THREE.Vector3; mid: THREE.Vector3; } | null>(null);
    const { toolMode } = useToolMode();
    const { isPlaying } = usePlayButtonStore();
    const { selectedAction } = useSelectedAction();
    const { selectedVersionStore } = useVersionContext();
    const { selectedVersion } = selectedVersionStore();
    const { setSelectedEventData } = useSelectedEventData();
    const { projectId } = useParams();

    const [firstSelectedPoint, setFirstSelectedPoint] = useState<{
        productUuid: string;
        modelUuid: string;
        pointUuid: string;
        actionUuid?: string;
    } | null>(null);

    const [connections, setConnections] = useState<ConnectionLine[]>([]);

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

        if (firstSelectedPoint?.pointUuid) {
            setSelectedEventData(eventData, firstSelectedPoint.pointUuid)
        }
    }

    useEffect(() => {
        const newConnections: ConnectionLine[] = [];

        const product = getProductById(selectedProduct.productUuid);
        if (!product || products.length === 0) return;

        product.eventDatas.forEach(event => {
            // Handle Conveyor points
            if (event.type === "transfer" && 'points' in event) {
                event.points.forEach(point => {
                    if (point.action?.triggers) {
                        point.action.triggers.forEach(trigger => {
                            if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
                                newConnections.push({
                                    id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
                                    startPointUuid: point.uuid,
                                    endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
                                    trigger
                                });
                            }
                        });
                    }
                });
            }
            // Handle Vehicle point
            else if (event.type === "vehicle" && 'point' in event) {
                const point = event.point;
                if (point.action?.triggers) {
                    point.action.triggers.forEach(trigger => {
                        if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
                            newConnections.push({
                                id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
                                startPointUuid: point.uuid,
                                endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
                                trigger
                            });
                        }
                    });
                }
            }
            // Handle Robotic Arm points
            else if (event.type === "roboticArm" && 'point' in event) {
                const point = event.point;
                point.actions?.forEach(action => {
                    action.triggers?.forEach(trigger => {
                        if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
                            newConnections.push({
                                id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
                                startPointUuid: point.uuid,
                                endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
                                trigger
                            });
                        }
                    });
                });
            }
            // Handle Machine point
            else if (event.type === "machine" && 'point' in event) {
                const point = event.point;
                if (point.action?.triggers) {
                    point.action.triggers.forEach(trigger => {
                        if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
                            newConnections.push({
                                id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
                                startPointUuid: point.uuid,
                                endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
                                trigger
                            });
                        }
                    });
                }
            }
            // Handle StorageUnit point
            else if (event.type === "storageUnit" && 'point' in event) {
                const point = event.point;
                if (point.action?.triggers) {
                    point.action.triggers.forEach(trigger => {
                        if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
                            newConnections.push({
                                id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
                                startPointUuid: point.uuid,
                                endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
                                trigger
                            });
                        }
                    });
                }
            }
            // Handle Human point
            else if (event.type === "human" && 'point' in event) {
                const point = event.point;
                point.actions?.forEach(action => {
                    action.triggers?.forEach(trigger => {
                        if (trigger.triggeredAsset && trigger.triggeredAsset.triggeredPoint) {
                            newConnections.push({
                                id: `${point.uuid}-${trigger.triggeredAsset.triggeredPoint.pointUuid}-${trigger.triggerUuid}`,
                                startPointUuid: point.uuid,
                                endPointUuid: trigger.triggeredAsset.triggeredPoint.pointUuid,
                                trigger
                            });
                        }
                    });
                });
            }
        });

        setConnections(newConnections);
    }, [products, selectedProduct.productUuid]);

    useEffect(() => {
        const canvasElement = gl.domElement;

        let drag = false;
        let isRightMouseDown = false;

        const onMouseDown = (evt: MouseEvent) => {
            if (selectedAsset) {
                clearSelectedAsset();
            }
            if (evt.button === 2) {
                isRightMouseDown = true;
                drag = false;
            }
        };

        const onMouseUp = (evt: MouseEvent) => {
            if (evt.button === 2) {
                isRightMouseDown = false;
            }
        }

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

        const handleRightClick = (evt: MouseEvent) => {
            if (drag) return;
            evt.preventDefault();

            const intersects = raycaster
                .intersectObjects(scene.children, true)
                .filter(
                    (intersect) =>
                        intersect.object.name === ('Event-Sphere')
                );
            if (intersects.length === 0) {
                setFirstSelectedPoint(null);
                return;
            };

            const currentObject = intersects[0].object;
            if (!currentObject || currentObject.name !== 'Event-Sphere') {
                setFirstSelectedPoint(null);
                return;
            };

            const modelUuid = currentObject.userData.modelUuid;
            const pointUuid = currentObject.userData.pointUuid;

            if (firstSelectedPoint && firstSelectedPoint.pointUuid === pointUuid) {
                setFirstSelectedPoint(null);
                return;
            }

            if (selectedProduct && getIsEventInProduct(selectedProduct.productUuid, modelUuid)) {

                const point = getPointByUuid(
                    selectedProduct.productUuid,
                    modelUuid,
                    pointUuid
                );

                const event = getEventByModelUuid(selectedProduct.productUuid, modelUuid);
                const clickedPointUuid = getPointUuidByActionUuid(selectedProduct.productUuid, selectedAction.actionId || '');

                if (!point || !event) {
                    setFirstSelectedPoint(null);
                    return;
                };

                let actionUuid: string | undefined;
                if ('action' in point && point.action) {
                    actionUuid = point.action.actionUuid;
                } else if ('actions' in point && point.actions.length === 1) {
                    actionUuid = point.actions[0].actionUuid;
                }

                if (!firstSelectedPoint) {
                    if (point.uuid !== clickedPointUuid) return;
                    setFirstSelectedPoint({
                        productUuid: selectedProduct.productUuid,
                        modelUuid,
                        pointUuid,
                        actionUuid: selectedAction.actionId || ''
                    });
                } else {
                    const trigger: TriggerSchema = {
                        triggerUuid: THREE.MathUtils.generateUUID(),
                        triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)} → ${pointUuid.slice(0, 4)}`,
                        triggerType: "onComplete",
                        delay: 0,
                        triggeredAsset: {
                            triggeredModel: {
                                modelName: event.modelName || 'Unknown',
                                modelUuid: modelUuid
                            },
                            triggeredPoint: {
                                pointName: 'Point',
                                pointUuid: point.uuid
                            },
                            triggeredAction: actionUuid ? {
                                actionName: getActionByUuid(selectedProduct.productUuid, actionUuid)?.actionName || 'Action',
                                actionUuid: actionUuid
                            } : null
                        }
                    };

                    if (firstSelectedPoint.actionUuid) {
                        const event = addTrigger(selectedProduct.productUuid, firstSelectedPoint.actionUuid, trigger);

                        if (event) {
                            updateBackend(
                                selectedProduct.productName,
                                selectedProduct.productUuid,
                                projectId || '',
                                event
                            );
                        }
                    }
                    setFirstSelectedPoint(null);
                }
            } else if (!getIsEventInProduct(selectedProduct.productUuid, modelUuid) && firstSelectedPoint) {
                handleAddEventToProduct({
                    event: eventStore.getState().getEventByModelUuid(modelUuid),
                    addEvent,
                    selectedProduct,
                    projectId: projectId || '',
                    versionId: selectedVersion?.versionId || '',
                })

                const point = getPointByUuid(
                    selectedProduct.productUuid,
                    modelUuid,
                    pointUuid
                );

                const event = getEventByModelUuid(selectedProduct.productUuid, modelUuid);

                if (!point || !event) {
                    setFirstSelectedPoint(null);
                    return;
                };

                let actionUuid: string | undefined;
                if ('action' in point && point.action) {
                    actionUuid = point.action.actionUuid;
                } else if ('actions' in point && point.actions.length === 1) {
                    actionUuid = point.actions[0].actionUuid;
                }

                const trigger: TriggerSchema = {
                    triggerUuid: THREE.MathUtils.generateUUID(),
                    triggerName: `Trigger ${firstSelectedPoint.pointUuid.slice(0, 4)} → ${pointUuid.slice(0, 4)}`,
                    triggerType: "onComplete",
                    delay: 0,
                    triggeredAsset: {
                        triggeredModel: {
                            modelName: event.modelName || 'Unknown',
                            modelUuid: modelUuid
                        },
                        triggeredPoint: {
                            pointName: 'Point',
                            pointUuid: point.uuid
                        },
                        triggeredAction: actionUuid ? {
                            actionName: getActionByUuid(selectedProduct.productUuid, actionUuid)?.actionName || 'Action',
                            actionUuid: actionUuid
                        } : null
                    }
                };

                if (firstSelectedPoint.actionUuid) {
                    const event = addTrigger(selectedProduct.productUuid, firstSelectedPoint.actionUuid, trigger);

                    if (event) {
                        updateBackend(
                            selectedProduct.productName,
                            selectedProduct.productUuid,
                            projectId || '',
                            event
                        );
                    }
                }
                setFirstSelectedPoint(null);
            } else if (firstSelectedPoint) {
                setFirstSelectedPoint(null);
            }
        };

        if (subModule === 'mechanics' && toolMode === 'cursor' && selectedAction.actionId && selectedAction.actionName) {
            canvasElement.addEventListener("mousedown", onMouseDown);
            canvasElement.addEventListener("mouseup", onMouseUp);
            canvasElement.addEventListener("mousemove", onMouseMove);
            canvasElement.addEventListener('contextmenu', handleRightClick);
        } else {
            setFirstSelectedPoint(null);
        }

        return () => {
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
            canvasElement.removeEventListener('contextmenu', handleRightClick);
        };

    }, [gl, subModule, selectedProduct, firstSelectedPoint, toolMode, selectedAction]);

    useFrame(() => {
        if (firstSelectedPoint) {
            raycaster.setFromCamera(pointer, camera);
            const intersects = raycaster.intersectObjects(scene.children, true).filter(
                (intersect) =>
                    !intersect.object.name.includes("Roof") &&
                    !intersect.object.name.includes("MeasurementReference") &&
                    !intersect.object.name.includes("agv-collider") &&
                    !intersect.object.name.includes("zonePlane") &&
                    !intersect.object.name.includes("SelectionGroup") &&
                    !intersect.object.name.includes("selectionAssetGroup") &&
                    !intersect.object.name.includes("SelectionGroupBoundingBoxLine") &&
                    !intersect.object.name.includes("SelectionGroupBoundingBox") &&
                    !intersect.object.name.includes("SelectionGroupBoundingLine") &&
                    intersect.object.type !== "GridHelper" &&
                    !intersect.object.name.includes("ArrowWithTube") &&
                    !intersect.object.parent?.name.includes("Zone") &&
                    intersect.object.type !== "Line2"
            );

            let point: THREE.Vector3 | null = null;

            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(scene.children, true).filter((intersect) => intersect.object.name === ('Event-Sphere'));

            if (sphereIntersects.length > 0 && sphereIntersects[0].object.uuid === firstSelectedPoint.pointUuid) {
                setHelperLineColor('red');
                setCurrentLine(null);
                return;
            }

            const startPoint = getWorldPositionFromScene(firstSelectedPoint.pointUuid);

            if (point && startPoint) {
                if (sphereIntersects.length > 0) {
                    point = sphereIntersects[0].object.getWorldPosition(new THREE.Vector3());
                }
                const distance = startPoint.distanceTo(point);
                const heightFactor = Math.max(0.5, distance * 0.2);
                const midPoint = new THREE.Vector3(
                    (startPoint.x + point.x) / 2,
                    Math.max(startPoint.y, point.y) + heightFactor,
                    (startPoint.z + point.z) / 2
                );

                const endPoint = point;

                setCurrentLine({
                    start: startPoint,
                    mid: midPoint,
                    end: endPoint,
                });

                setHelperLineColor(sphereIntersects.length > 0 ? "#6cf542" : "red");
            } else {
                setCurrentLine(null);
            }
        } else {
            setCurrentLine(null);
        }

    })

    const getWorldPositionFromScene = (pointUuid: string): THREE.Vector3 | null => {
        const pointObj = scene.getObjectByProperty("uuid", pointUuid);
        if (!pointObj) return null;

        const worldPosition = new THREE.Vector3();
        pointObj.getWorldPosition(worldPosition);
        return worldPosition;
    };

    const removeConnection = (connection: ConnectionLine) => {
        if (connection.trigger.triggerUuid) {
            const event = removeTrigger(selectedProduct.productUuid, connection.trigger.triggerUuid);
            if (event) {
                updateBackend(
                    selectedProduct.productName,
                    selectedProduct.productUuid,
                    projectId || '',
                    event
                );
            }
        }
    };

    return (
        <group name="simulationConnectionGroup" visible={!isPlaying}>
            {connections.map((connection) => {
                const startPoint = getWorldPositionFromScene(connection.startPointUuid);
                const endPoint = getWorldPositionFromScene(connection.endPointUuid);

                if (!startPoint || !endPoint) return null;

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

                return (
                    <QuadraticBezierLine
                        key={connection.id}
                        ref={(el) => (groupRefs.current[connection.id] = el!)}
                        start={startPoint.toArray()}
                        end={endPoint.toArray()}
                        mid={midPoint.toArray()}
                        color={toolMode === '3D-Delete' && hoveredLineKey === connection.id ? "red" : "#42a5f5"}
                        lineWidth={4}
                        dashed={toolMode === '3D-Delete' && hoveredLineKey === connection.id ? false : true}
                        dashSize={0.75}
                        dashScale={20}
                        // onPointerOver={() => setHoveredLineKey(connection.id)}
                        // onPointerOut={() => setHoveredLineKey(null)}
                        // onClick={() => {
                        //     if (toolMode === '3D-Delete') {
                        //         setHoveredLineKey(null);
                        //         setCurrentLine(null);
                        //         removeConnection(connection);
                        //     }
                        // }}
                        userData={connection.trigger}
                    />
                );
            })}

            <Arrows connections={connections} />

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

        </group>
    );
}

export default TriggerConnector;