import { useEffect, useRef, useState } from "react";
import * as THREE from "three";
import useModuleStore, { useSubModuleStore } from "../../../../../store/useModuleStore";
import { useToolMode } from "../../../../../store/builder/store";
import { TransformControls } from "@react-three/drei";
import { detectModifierKeys } from "../../../../../utils/shortcutkeys/detectModifierKeys";
import { useSelectedEventSphere, useSelectedEventData, useDeletableEventSphere } from "../../../../../store/simulation/useSimulationStore";
import { useThree } from "@react-three/fiber";
import { usePlayButtonStore } from "../../../../../store/usePlayButtonStore";
import { upsertProductOrEventApi } from "../../../../../services/simulation/products/UpsertProductOrEventApi";
import { useProductContext } from "../../../products/productContext";
import { useParams } from "react-router-dom";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useSceneContext } from "../../../../scene/sceneContext";

import PointInstances from "../instances/pointInstances";

function PointsCreator() {
    const { gl, raycaster, scene, pointer, camera } = useThree();
    const { subModule } = useSubModuleStore();
    const { toolMode } = useToolMode();
    const { activeModule } = useModuleStore();
    const { selectedProductStore } = useProductContext();
    const { eventStore, productStore } = useSceneContext();
    const { getEventByModelUuid } = eventStore();
    const { getEventByModelUuid: getEventByModelUuidFromProduct, updatePoint: updatePointFromProduct, getPointByUuid: getPointByUuidFromProduct, getTriggersByTriggeredPointUuid, removeTrigger, removePoint } = productStore();
    const { selectedProduct } = selectedProductStore();
    const transformRef = useRef<any>(null);
    const [transformMode, setTransformMode] = useState<"translate" | "rotate" | null>(null);
    const { selectedEventSphere, clearSelectedEventSphere, } = useSelectedEventSphere();
    const { clearDeletableEventSphere } = useDeletableEventSphere();
    const { setSelectedEventData, clearSelectedEventData } = useSelectedEventData();
    const { isPlaying } = usePlayButtonStore();
    const { selectedVersionStore } = useVersionContext();
    const { selectedVersion } = selectedVersionStore();
    const { projectId } = useParams();

    useEffect(() => {
        clearSelectedEventSphere();
        clearSelectedEventData();
        clearDeletableEventSphere();
    }, [toolMode, activeModule])

    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) {
            const eventData = getEventByModelUuid(
                selectedEventSphere.userData.modelUuid
            );

            if (eventData) {
                setSelectedEventData(eventData, selectedEventSphere.userData.pointUuid);
            } else {
                clearSelectedEventData();
            }
        } else {
            clearSelectedEventData();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [selectedEventSphere]);

    useEffect(() => {
        const handleKeyDown = (e: KeyboardEvent) => {
            const keyCombination = detectModifierKeys(e);
            if (!selectedEventSphere) return;
            if (keyCombination === "G") {
                setTransformMode((prev) => (prev === "translate" ? null : "translate"));
            }
            if (keyCombination === "R") {
                setTransformMode((prev) => (prev === "rotate" ? null : "rotate"));
            }
            if (keyCombination === 'DELETE') {
                deletePointfromConveyor(selectedEventSphere);
            }
        };

        window.addEventListener("keydown", handleKeyDown);
        return () => window.removeEventListener("keydown", handleKeyDown);
    }, [selectedEventSphere]);

    const deletePointfromConveyor = (selectedEventSphere: THREE.Mesh) => {
        const eventModel = getEventByModelUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);
        if (!eventModel || eventModel.type !== 'transfer' || eventModel.points.length < 2) return;

        const triggers = getTriggersByTriggeredPointUuid(selectedProduct.productUuid, selectedEventSphere.userData.pointUuid);

        const updatedEvents: EventsSchema[] = [];
        if (triggers.length > 0) {
            triggers.map((trigger) => {
                const event = removeTrigger(selectedProduct.productUuid, trigger.triggerUuid);
                if (event) {
                    updatedEvents.push(event);
                }
            })
        }

        const event = removePoint(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)

        if (event) {
            updatedEvents.push(event);
        }

        if (updatedEvents.length > 0) {
            updatedEvents.map((updatedEvent) => {
                updateBackend(
                    selectedProduct.productName,
                    selectedProduct.productUuid,
                    projectId || '',
                    updatedEvent
                );
            })
        }
    }

    const updatePointToState = (selectedEventSphere: THREE.Mesh) => {
        const position = [
            selectedEventSphere.position.x,
            selectedEventSphere.position.y,
            selectedEventSphere.position.z,
        ];
        const rotation = [
            selectedEventSphere.rotation.x,
            selectedEventSphere.rotation.y,
            selectedEventSphere.rotation.z,
        ];

        const event = getEventByModelUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid);

        if (event && selectedProduct.productUuid !== '') {

            const updatedPoint = JSON.parse(
                JSON.stringify(
                    getPointByUuidFromProduct(selectedProduct.productUuid, selectedEventSphere.userData.modelUuid, selectedEventSphere.userData.pointUuid)
                )
            );
            if (updatedPoint) {
                updatedPoint.position = position;
                updatedPoint.rotation = rotation;

                const updatedEvent = updatePointFromProduct(
                    selectedProduct.productUuid,
                    selectedEventSphere.userData.modelUuid,
                    selectedEventSphere.userData.pointUuid,
                    updatedPoint
                )
                if (updatedEvent) {
                    updateBackend(
                        selectedProduct.productName,
                        selectedProduct.productUuid,
                        projectId || '',
                        updatedEvent
                    );
                }
            }
        }
    };

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

        let drag = false;
        let isMouseDown = false;

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

        const onMouseUp = () => {
            if (selectedEventSphere && !drag) {
                raycaster.setFromCamera(pointer, camera);
                const intersects = raycaster.intersectObjects(scene.children, true).filter((intersect) => intersect.object.name === "Event-Sphere");
                if (intersects.length === 0) {
                    clearSelectedEventSphere();
                    setTransformMode(null);
                }
            }
        };

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

        if (subModule === "mechanics") {
            canvasElement.addEventListener("mousedown", onMouseDown);
            canvasElement.addEventListener("mouseup", onMouseUp);
            canvasElement.addEventListener("mousemove", onMouseMove);
        }

        return () => {
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
        };
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [gl, subModule, selectedEventSphere]);

    return (
        <>
            {activeModule === "simulation" && (
                <>
                    <group name="EventPointsGroup" visible={!isPlaying}>
                        <PointInstances />
                    </group>

                    {selectedEventSphere && transformMode && (
                        <TransformControls
                            ref={transformRef}
                            object={selectedEventSphere}
                            mode={transformMode}
                            onMouseUp={(e) => {
                                updatePointToState(selectedEventSphere);
                            }}
                        />
                    )}
                </>
            )}
        </>
    );
}

export default PointsCreator;
