import { useEffect } from "react";
import * as Types from '../../../types/world/worldTypes';
import { useActiveLayer, useDeletedLines, useDeletePointOrLine, useToolMode, useMovePoint, useNewLines, useRemovedLayer, useSocketStore, useToggleView, useUpdateScene } from "../../../store/store";
import Layer2DVisibility from "../geomentries/layers/layer2DVisibility";
import { useFrame, useThree } from "@react-three/fiber";
import DeletableLineorPoint from "../functions/deletableLineOrPoint";
import removeSoloPoint from "../geomentries/points/removeSoloPoint";
import removeReferenceLine from "../geomentries/lines/removeReferenceLine";
import DeleteLayer from "../geomentries/layers/deleteLayer";
import { getLines } from "../../../services/factoryBuilder/lines/getLinesApi";
import objectLinesToArray from "../geomentries/lines/lineConvertions/objectLinesToArray";
import loadInitialPoint from "../IntialLoad/loadInitialPoint";
import loadInitialLine from "../IntialLoad/loadInitialLine";
import deletePoint from "../geomentries/points/deletePoint";
import deleteLine from "../geomentries/lines/deleteLine";
import drawWall from "../geomentries/lines/drawWall";
import drawOnlyFloor from "../geomentries/floors/drawOnlyFloor";
import addDragControl from "../eventDeclaration/dragControlDeclaration";

const FloorPlanGroup = ({ floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, floorGroup, currentLayerPoint, dragPointControls, hoveredDeletablePoint, hoveredDeletableLine, plane, line, lines, onlyFloorline, onlyFloorlines, ReferenceLineMesh, LineCreated, isSnapped, ispreSnapped, snappedPoint, isSnappedUUID, isAngleSnapped, anglesnappedPoint }: any) => {
    const state = useThree();
    const { scene, camera, gl, raycaster, controls } = state;
    const { activeLayer, setActiveLayer } = useActiveLayer();
    const { toggleView, setToggleView } = useToggleView();
    const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
    const { toolMode, setToolMode } = useToolMode();
    const { movePoint, setMovePoint } = useMovePoint();
    const { removedLayer, setRemovedLayer } = useRemovedLayer();
    const { updateScene, setUpdateScene } = useUpdateScene();
    const { newLines, setNewLines } = useNewLines();
    const { deletedLines, setDeletedLines } = useDeletedLines();
    const { socket } = useSocketStore();

    useEffect(() => {
        addDragControl(dragPointControls, currentLayerPoint, state, floorPlanGroupPoint, floorPlanGroupLine, lines, onlyFloorlines, socket);
    }, [state]);

    useEffect(() => {
        const email = localStorage.getItem('email')
        const organization = (email!.split("@")[1]).split(".")[0];

        // Load data from localStorage if available
        getLines(organization).then((data) => {

            const Lines: Types.Lines = objectLinesToArray(data);

            // const data = localStorage.getItem("Lines");

            if (Lines) {
                lines.current = Lines;
                loadInitialPoint(lines, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
                loadInitialLine(floorPlanGroupLine, lines);
                setUpdateScene(true);
            }
        })
    }, []);

    useEffect(() => {
        if (!toggleView) {
            removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
            removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
        }
    }, [toggleView]);

    useEffect(() => {
        if (toolMode === "Wall" || toolMode === "Floor") {
            setDeletePointOrLine(false);
            setMovePoint(false);
        } else {
            removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
            removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
        }
    }, [toolMode]);

    useEffect(() => {
        if (movePoint) {
            setToolMode(null);
            setDeletePointOrLine(false);
            if (dragPointControls.current) {
                dragPointControls.current.enabled = true;
            }
        } else {
            if (dragPointControls.current) {
                dragPointControls.current.enabled = false;
            }
        }
    }, [movePoint, toolMode]);

    useEffect(() => {
        if (deletePointOrLine) {
            setToolMode(null);
            setMovePoint(false);
        }
    }, [deletePointOrLine]);

    useEffect(() => {
        Layer2DVisibility(activeLayer, floorPlanGroup, floorPlanGroupLine, floorPlanGroupPoint, currentLayerPoint, dragPointControls);
    }, [activeLayer]);

    useEffect(() => {
        if (removedLayer !== null) {
            DeleteLayer(removedLayer, lines, floorPlanGroupLine, floorPlanGroupPoint, onlyFloorlines, floorGroup, setDeletedLines, setRemovedLayer, socket);
        }
    }, [removedLayer]);

    useEffect(() => {

        const canvasElement = gl.domElement;

        let drag = false;
        let isLeftMouseDown = false;

        const onMouseDown = (evt: any) => {
            if (evt.button === 0) {
                isLeftMouseDown = true;
                drag = false;
            }
        };

        const onMouseUp = (evt: any) => {
            if (evt.button === 0) {
                isLeftMouseDown = false;
            }
            if (controls) {
                (controls as any).enabled = true;
            }
        }

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

        const onContextMenu = (e: any) => {
            e.preventDefault();
            if (toolMode === "Wall" || toolMode === "Floor") {
                removeSoloPoint(line, floorPlanGroupLine, floorPlanGroupPoint);
                removeReferenceLine(floorPlanGroup, ReferenceLineMesh, LineCreated, line);
            }
        };

        const onMouseClick = (evt: any) => {
            if (!plane.current || drag) return;

            if (deletePointOrLine) {
                if (hoveredDeletablePoint.current !== null) {
                    deletePoint(hoveredDeletablePoint, onlyFloorlines, floorPlanGroupPoint, floorPlanGroupLine, lines, setDeletedLines, socket);
                }
                if (hoveredDeletableLine.current !== null) {
                    deleteLine(hoveredDeletableLine, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroupPoint, setDeletedLines, socket);
                }
            }

            if (toolMode === "Wall") {
                drawWall(raycaster, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
            }

            if (toolMode === "Floor") {
                drawOnlyFloor(raycaster, state, camera, plane, floorPlanGroupPoint, snappedPoint, isSnapped, isSnappedUUID, line, ispreSnapped, anglesnappedPoint, isAngleSnapped, onlyFloorline, onlyFloorlines, lines, floorPlanGroupLine, floorPlanGroup, ReferenceLineMesh, LineCreated, currentLayerPoint, dragPointControls, setNewLines, setDeletedLines, activeLayer, socket);
            }
        }

        if (deletePointOrLine || toolMode === "Wall" || toolMode === "Floor") {
            canvasElement.addEventListener("mousedown", onMouseDown);
            canvasElement.addEventListener("mouseup", onMouseUp);
            canvasElement.addEventListener("mousemove", onMouseMove);
            canvasElement.addEventListener("click", onMouseClick);
            canvasElement.addEventListener("contextmenu", onContextMenu);
        }

        return () => {
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
            canvasElement.removeEventListener("click", onMouseClick);
            canvasElement.removeEventListener("contextmenu", onContextMenu);
        };
    }, [deletePointOrLine, toolMode, activeLayer])


    useFrame(() => {
        if (deletePointOrLine) {
            DeletableLineorPoint(state, plane, floorPlanGroupLine, floorPlanGroupPoint, hoveredDeletableLine, hoveredDeletablePoint);
        }
    })

    return (
        <group ref={floorPlanGroup} visible={toggleView} name="floorPlanGroup">
            <group ref={floorPlanGroupLine} name="floorPlanGroupLine"></group>
            <group ref={floorPlanGroupPoint} name="floorPlanGroupPoint"></group>
        </group>
    )
}

export default FloorPlanGroup;