import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import { SelectionHelper } from "../selectionHelper";
import { SelectionBox } from "three/examples/jsm/interactive/SelectionBox";

import useModuleStore from "../../../../../store/useModuleStore";
import { useParams } from "react-router-dom";
import { getUserData } from "../../../../../functions/getUserData";
import { useSceneContext } from "../../../sceneContext";
import { useVersionContext } from "../../../../builder/version/versionContext";
import { useSocketStore, useToggleView, useToolMode, } from "../../../../../store/builder/store";
import { useSelectedPoints } from "../../../../../store/simulation/useSimulationStore";
import { useBuilderStore } from "../../../../../store/builder/useBuilderStore";
import MoveControls2D from "./moveControls2D";

// import { deleteAisleApi } from "../../../../../services/factoryBuilder/aisle/deleteAisleApi";
// import { deleteWallApi } from "../../../../../services/factoryBuilder/wall/deleteWallApi";
// import { deleteFloorApi } from "../../../../../services/factoryBuilder/floor/deleteFloorApi";
// import { upsertFloorApi } from "../../../../../services/factoryBuilder/floor/upsertFloorApi";
// import { deleteZoneApi } from "../../../../../services/factoryBuilder/zone/deleteZoneApi";
// import { upsertZoneApi } from "../../../../../services/factoryBuilder/zone/upsertZoneApi";

const SelectionControls2D: React.FC = () => {
    const { camera, controls, gl, scene, raycaster, pointer } = useThree();
    const { toggleView } = useToggleView();
    const { selectedPoints, setSelectedPoints, clearSelectedPoints } = useSelectedPoints();
    const [movedObjects, setMovedObjects] = useState<THREE.Object3D[]>([]);
    const [rotatedObjects, setRotatedObjects] = useState<THREE.Object3D[]>([]);
    const [copiedObjects, setCopiedObjects] = useState<THREE.Object3D[]>([]);
    const [pastedObjects, setpastedObjects] = useState<THREE.Object3D[]>([]);
    const [duplicatedObjects, setDuplicatedObjects] = useState<THREE.Object3D[]>([]);
    const { activeModule } = useModuleStore();
    const { socket } = useSocketStore();
    const selectionBox = useMemo(() => new SelectionBox(camera, scene), [camera, scene]);
    const { toolMode } = useToolMode();
    const { selectedVersionStore } = useVersionContext();
    const { selectedVersion } = selectedVersionStore();
    const { projectId } = useParams();
    const { hoveredLine, hoveredPoint } = useBuilderStore();
    const { aisleStore, wallStore, floorStore, zoneStore } = useSceneContext();
    const { removePoint: removeAislePoint } = aisleStore();
    const { removePoint: removeWallPoint } = wallStore();
    const { removePoint: removeFloorPoint } = floorStore();
    const { removePoint: removeZonePoint } = zoneStore();

    const isDragging = useRef(false);
    const isLeftMouseDown = useRef(false);
    const isSelecting = useRef(false);
    const isRightClick = useRef(false);
    const rightClickMoved = useRef(false);
    const isCtrlSelecting = useRef(false);
    const isShiftSelecting = useRef(false);
    const { userId, organization } = getUserData();

    useEffect(() => {
        if (!camera || !scene || !toggleView) return;

        const canvasElement = gl.domElement;
        canvasElement.tabIndex = 0;

        const helper = new SelectionHelper(gl);

        const onPointerDown = (event: PointerEvent) => {
            if (event.button === 2) {
                isRightClick.current = true;
                rightClickMoved.current = false;
            } else if (event.button === 0) {
                isSelecting.current = false;
                isCtrlSelecting.current = event.ctrlKey;
                isShiftSelecting.current = event.shiftKey;
                isLeftMouseDown.current = true;
                isDragging.current = false;
                if (event.ctrlKey && duplicatedObjects.length === 0) {
                    if (controls) (controls as any).enabled = false;
                    selectionBox.startPoint.set(pointer.x, pointer.y, 0);
                }
            }
        };

        const onPointerMove = (event: PointerEvent) => {
            if (isRightClick.current) {
                rightClickMoved.current = true;
            }
            if (isLeftMouseDown.current) {
                isDragging.current = true;
            }
            isSelecting.current = true;
            if (helper.isDown && event.ctrlKey && duplicatedObjects.length === 0 && isCtrlSelecting.current) {
                selectionBox.endPoint.set(pointer.x, pointer.y, 0);
            }
        };

        const onPointerUp = (event: PointerEvent) => {
            if (event.button === 2 && !event.ctrlKey && !event.shiftKey) {
                isRightClick.current = false;
                if (!rightClickMoved.current) {
                    clearSelection();
                }
                return;
            }

            if (isSelecting.current && isCtrlSelecting.current) {
                isCtrlSelecting.current = false;
                isSelecting.current = false;
                if (event.ctrlKey && duplicatedObjects.length === 0) {
                    selectAssets();
                }
            } else if (!isSelecting.current && selectedPoints.length > 0 && ((!event.ctrlKey && !event.shiftKey && pastedObjects.length === 0 && duplicatedObjects.length === 0 && movedObjects.length === 0 && rotatedObjects.length === 0) || event.button !== 0)) {
                clearSelection();
                helper.enabled = true;
                isCtrlSelecting.current = false;
            } else if (controls) {
                (controls as any).enabled = true;
            }

            if (!isDragging.current && isLeftMouseDown.current && isShiftSelecting.current && event.shiftKey) {
                isShiftSelecting.current = false;
                isLeftMouseDown.current = false;
                isDragging.current = false;

            } else if (controls) {
                (controls as any).enabled = true;
            }
        };

        const onKeyDown = (event: KeyboardEvent) => {
            if (movedObjects.length > 0 || rotatedObjects.length > 0) return;
            if (event.key.toLowerCase() === "escape") {
                event.preventDefault();
                clearSelection();
            }
            if (event.key.toLowerCase() === "delete") {
                event.preventDefault();
                deleteSelection();
            }
        };

        const onContextMenu = (event: MouseEvent) => {
            event.preventDefault();
            if (!rightClickMoved.current) {
                clearSelection();
            }
            rightClickMoved.current = false;
        };

        if (toggleView && toolMode === 'move') {
            helper.enabled = true;
            canvasElement.addEventListener("pointermove", onPointerMove);
            canvasElement.addEventListener("pointerup", onPointerUp);
            canvasElement.addEventListener("pointerdown", onPointerDown);
            canvasElement.addEventListener("contextmenu", onContextMenu);
            canvasElement.addEventListener("keydown", onKeyDown);
        } else {
            helper.enabled = false;
            helper.dispose();
        }

        return () => {
            canvasElement.removeEventListener("pointerdown", onPointerDown);
            canvasElement.removeEventListener("pointermove", onPointerMove);
            canvasElement.removeEventListener("contextmenu", onContextMenu);
            canvasElement.removeEventListener("pointerup", onPointerUp);
            canvasElement.removeEventListener("keydown", onKeyDown);
            helper.enabled = false;
            helper.dispose();
        };
    }, [camera, controls, scene, toggleView, selectedPoints, copiedObjects, pastedObjects, duplicatedObjects, movedObjects, socket, rotatedObjects, toolMode, hoveredLine, hoveredPoint]);

    useEffect(() => {
        if (toolMode !== 'move' || !toggleView) {
            clearSelection();
        }
    }, [activeModule, toolMode, toggleView]);

    const selectAssets = useCallback(() => {
        selectionBox.endPoint.set(pointer.x, pointer.y, 0);
        if (controls) (controls as any).enabled = true;

        let selectedObjects = selectionBox.select();
        let Objects = new Set<THREE.Object3D>();

        selectedObjects.forEach((object) => {
            let currentObject: THREE.Object3D | null = object;
            while (currentObject) {
                if (currentObject.userData.pointUuid) {
                    Objects.add(currentObject);
                    break;
                }
                currentObject = currentObject.parent || null;
            }
        });

        if (Objects.size === 0) {
            clearSelection();
            return;
        }

        const updatedSelections = new Set<THREE.Object3D>(selectedPoints);

        Objects.forEach((obj) => {
            const existing = Array.from(updatedSelections).find((o) => o.userData?.pointUuid === obj.userData?.pointUuid);

            if (existing) {
                updatedSelections.delete(existing);
            } else {
                updatedSelections.add(obj);
            }
        });

        const selected = Array.from(updatedSelections);

        setSelectedPoints(selected);

    }, [selectionBox, pointer, controls, selectedPoints, setSelectedPoints]);

    const clearSelection = () => {
        setpastedObjects([]);
        setDuplicatedObjects([]);
        clearSelectedPoints();
    };

    const deleteSelection = () => {
        if (selectedPoints.length > 0 && duplicatedObjects.length === 0) {

            selectedPoints.forEach((selectedPoint) => {
                if (selectedPoint.userData.pointUuid) {
                    const point: Point = selectedPoint.userData as Point;
                    if (point.pointType === 'Aisle') {
                        const removedAisles = removeAislePoint(point.pointUuid);
                        if (removedAisles.length > 0) {
                            removedAisles.forEach(aisle => {
                                if (projectId) {

                                    // API

                                    // deleteAisleApi(aisle.aisleUuid, projectId, selectedVersion?.versionId || '');

                                    // SOCKET

                                    const data = {
                                        projectId: projectId,
                                        versionId: selectedVersion?.versionId || '',
                                        userId: userId,
                                        organization: organization,
                                        aisleUuid: aisle.aisleUuid
                                    }

                                    socket.emit('v1:model-aisle:delete', data);
                                }
                            });
                        }
                    }
                    if (point.pointType === 'Wall') {
                        const removedWalls = removeWallPoint(point.pointUuid);
                        if (removedWalls.length > 0) {
                            removedWalls.forEach(wall => {
                                if (projectId) {

                                    // API

                                    // deleteWallApi(projectId, selectedVersion?.versionId || '', wall.wallUuid);

                                    // SOCKET

                                    const data = {
                                        wallUuid: wall.wallUuid,
                                        projectId: projectId,
                                        versionId: selectedVersion?.versionId || '',
                                        userId: userId,
                                        organization: organization
                                    }

                                    socket.emit('v1:model-Wall:delete', data);
                                }
                            });
                        }
                    }
                    if (point.pointType === 'Floor') {
                        const { removedFloors, updatedFloors } = removeFloorPoint(point.pointUuid);
                        if (removedFloors.length > 0) {
                            removedFloors.forEach(floor => {
                                if (projectId) {

                                    // API

                                    // deleteFloorApi(projectId, selectedVersion?.versionId || '', floor.floorUuid);

                                    // SOCKET

                                    const data = {
                                        floorUuid: floor.floorUuid,
                                        projectId: projectId,
                                        versionId: selectedVersion?.versionId || '',
                                        userId: userId,
                                        organization: organization
                                    }

                                    socket.emit('v1:model-Floor:delete', data);
                                }
                            });
                        }
                        if (updatedFloors.length > 0) {
                            updatedFloors.forEach(floor => {
                                if (projectId) {

                                    // API

                                    // upsertFloorApi(projectId, selectedVersion?.versionId || '', floor);

                                    // SOCKET

                                    const data = {
                                        floorData: floor,
                                        projectId: projectId,
                                        versionId: selectedVersion?.versionId || '',
                                        userId: userId,
                                        organization: organization
                                    }

                                    socket.emit('v1:model-Floor:add', data);
                                }
                            });
                        }
                    }
                    if (point.pointType === 'Zone') {
                        const { removedZones, updatedZones } = removeZonePoint(point.pointUuid);
                        if (removedZones.length > 0) {
                            removedZones.forEach(zone => {
                                if (projectId) {

                                    // API

                                    // deleteZoneApi(projectId, selectedVersion?.versionId || '', zone.zoneUuid);

                                    // SOCKET

                                    const data = {
                                        zoneUuid: zone.zoneUuid,
                                        projectId: projectId,
                                        versionId: selectedVersion?.versionId || '',
                                        userId: userId,
                                        organization: organization
                                    }

                                    socket.emit('v1:zone:delete', data);
                                }
                            });
                        }
                        if (updatedZones.length > 0) {
                            updatedZones.forEach(zone => {
                                if (projectId) {

                                    // API

                                    // upsertZoneApi(projectId, selectedVersion?.versionId || '', zone);

                                    // SOCKET

                                    const data = {
                                        zoneData: zone,
                                        projectId: projectId,
                                        versionId: selectedVersion?.versionId || '',
                                        userId: userId,
                                        organization: organization
                                    }

                                    socket.emit('v1:zone:add', data);
                                }
                            });
                        }
                    }
                }
            })

        }
        echo.success("Selected points removed!");
        clearSelection();
    };

    return (
        <>
            <MoveControls2D movedObjects={movedObjects} setMovedObjects={setMovedObjects} pastedObjects={pastedObjects} setpastedObjects={setpastedObjects} duplicatedObjects={duplicatedObjects} setDuplicatedObjects={setDuplicatedObjects} rotatedObjects={rotatedObjects} setRotatedObjects={setRotatedObjects} />

        </>
    );
};

export default SelectionControls2D;
