import { useEffect } from "react";
import { useDeleteModels, useDeletePointOrLine, useObjectPosition, useObjectRotation, useObjectScale, useSelectedWallItem, useSocketStore, useWallItems } from "../../../store/store";
import { Csg } from "../csg/csg";
import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
import * as THREE from "three";
import { useThree } from "@react-three/fiber";
import handleMeshMissed from "../eventFunctions/handleMeshMissed";
import DeleteWallItems from "../geomentries/walls/deleteWallItems";
import loadInitialWallItems from "../../scene/IntialLoad/loadInitialWallItems";
import AddWallItems from "../geomentries/walls/addWallItems";


const WallItemsGroup = ({ currentWallItem, AssetConfigurations, hoveredDeletableWallItem, selectedItemsIndex, setSelectedItemsIndex, CSGGroup }: any) => {
    const { deleteModels, setDeleteModels } = useDeleteModels();
    const { wallItems, setWallItems } = useWallItems();
    const { objectPosition, setObjectPosition } = useObjectPosition();
    const { objectScale, setObjectScale } = useObjectScale();
    const { objectRotation, setObjectRotation } = useObjectRotation();
    const { deletePointOrLine, setDeletePointOrLine } = useDeletePointOrLine();
    const { selectedWallItem, setSelectedWallItem } = useSelectedWallItem();
    const { socket } = useSocketStore();
    const state = useThree();
    const { pointer, camera, raycaster } = state;


    useEffect(() => {
        // Load Wall Items from the backend
        loadInitialWallItems(setWallItems, AssetConfigurations);
    }, []);


    //////////  Update the Scale value changes in thewallItems State  //////////

    //////////  Update the Position value changes  in the selected item  //////////

    //////////  Update the Rotation value changes  in the selected item  //////////

    useEffect(() => {
        if (objectScale.x && objectScale.y && objectScale.z) {
            let ScaledWallItems: Types.wallItems = [];
            wallItems.forEach((items: any) => {
                if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
                    items.scale = [objectScale.x, objectScale.y, objectScale.z];
                }
                ScaledWallItems.push(items);
            });
            setWallItems(ScaledWallItems);
        }
    }, [objectScale]);

    useEffect(() => {
        if (objectPosition.x && objectPosition.y && objectPosition.z) {
            let ScaledWallItems: Types.wallItems = [];
            wallItems.forEach((items: any) => {
                if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
                    items.position = [objectPosition.x, objectPosition.y, objectPosition.z];
                }
                ScaledWallItems.push(items);
            });
            setWallItems(ScaledWallItems);
        }
    }, [objectPosition]);

    useEffect(() => {
        if (objectRotation.x && objectRotation.y && objectRotation.z) {
            let ScaledWallItems: Types.wallItems = [];
            wallItems.forEach((items: any) => {
                if (items.model?.uuid === currentWallItem.current?.parent?.uuid) {
                    const radiansX = objectRotation.x * (Math.PI / 180);
                    const radiansY = objectRotation.y * (Math.PI / 180);
                    const radiansZ = objectRotation.z * (Math.PI / 180);
                    const quaternion = new THREE.Quaternion().setFromEuler(
                        new THREE.Euler(radiansX, radiansY, radiansZ)
                    );
                    items.quaternion = [quaternion.x, quaternion.y, quaternion.z, quaternion.w];
                }
                ScaledWallItems.push(items);
            });
            setWallItems(ScaledWallItems);
        }
    }, [objectRotation]);

    useEffect(() => {
        const canvasElement = state.gl.domElement;
        function handlePointerMove(e: any) {
            if (selectedItemsIndex !== null && !deletePointOrLine && e.buttons === 1) {
                const Raycaster = state.raycaster;
                const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
                const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));

                if (Object) {
                    (state.controls as any)!.enabled = false;
                    setWallItems((prevItems: any) => {
                        const updatedItems = [...prevItems];
                        let position: [number, number, number] = [0, 0, 0];

                        if (updatedItems[selectedItemsIndex].type === "Fixed-Move") {
                            position = [Object!.point.x, Math.floor(Object!.point.y / CONSTANTS.wallConfig.height) * CONSTANTS.wallConfig.height, Object!.point.z];
                        } else if (updatedItems[selectedItemsIndex].type === "Free-Move") {
                            position = [Object!.point.x, Object!.point.y, Object!.point.z];
                        }

                        requestAnimationFrame(() => {
                            setObjectPosition(new THREE.Vector3(...position));
                            setObjectRotation({
                                x: THREE.MathUtils.radToDeg(Object!.object.rotation.x),
                                y: THREE.MathUtils.radToDeg(Object!.object.rotation.y),
                                z: THREE.MathUtils.radToDeg(Object!.object.rotation.z),
                            });
                        });

                        updatedItems[selectedItemsIndex] = {
                            ...updatedItems[selectedItemsIndex],
                            position: position,
                            quaternion: Object!.object.quaternion.clone() as Types.QuaternionType,
                        };

                        return updatedItems;
                    });
                }
            }
        }

        async function handlePointerUp() {
            const Raycaster = state.raycaster;
            const intersects = Raycaster.intersectObjects(CSGGroup.current?.children[0].children!, true);
            const Object = intersects.find((child) => child.object.name.includes("WallRaycastReference"));
            if (Object) {
                if (selectedItemsIndex !== null) {
                    let currentItem: any = null;
                    setWallItems((prevItems: any) => {
                        const updatedItems = [...prevItems];
                        const WallItemsForStorage = updatedItems.map((item) => {
                            const { model, ...rest } = item;
                            return {
                                ...rest,
                                modeluuid: model?.uuid,
                            };
                        });

                        currentItem = updatedItems[selectedItemsIndex];
                        localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
                        return updatedItems;
                    });

                    setTimeout(async () => {

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

                        //REST

                        // await setWallItem(
                        //   organization,
                        //   currentItem?.model?.uuid,
                        //   currentItem.modelname,
                        //   currentItem.type!,
                        //   currentItem.csgposition!,
                        //   currentItem.csgscale!,
                        //   currentItem.position,
                        //   currentItem.quaternion,
                        //   currentItem.scale!,
                        // )

                        //SOCKET

                        const data = {
                            organization: organization,
                            modeluuid: currentItem.model?.uuid!,
                            modelname: currentItem.modelname!,
                            type: currentItem.type!,
                            csgposition: currentItem.csgposition!,
                            csgscale: currentItem.csgscale!,
                            position: currentItem.position!,
                            quaternion: currentItem.quaternion,
                            scale: currentItem.scale!,
                            socketId: socket.id
                        }

                        socket.emit('v1:wallItems:set', data);
                    }, 0);
                    (state.controls as any)!.enabled = true;
                }
            }
        }

        canvasElement.addEventListener("pointermove", handlePointerMove);
        canvasElement.addEventListener("pointerup", handlePointerUp);

        return () => {
            canvasElement.removeEventListener("pointermove", handlePointerMove);
            canvasElement.removeEventListener("pointerup", handlePointerUp);
        };
    }, [selectedItemsIndex]);

    useEffect(() => {
        const canvasElement = state.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 (!drag && deleteModels) {
                    DeleteWallItems(hoveredDeletableWallItem, setWallItems, wallItems, socket);
                }
            }
        };

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

        const onDrop = (event: any) => {

            if (!event.dataTransfer?.files[0]) return
            pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
            pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
            raycaster.setFromCamera(pointer, camera);

            if (AssetConfigurations[(event.dataTransfer.files[0].name.split('.'))[0]]) {
                const selected = (event.dataTransfer.files[0].name.split('.'))[0];

                if (AssetConfigurations[selected]?.type) {
                    AddWallItems(selected, raycaster, CSGGroup, AssetConfigurations, setWallItems, socket);
                }
                event.preventDefault();
            }
        }

        const onDragOver = (event: any) => {
            event.preventDefault();
        };

        canvasElement.addEventListener("mousedown", onMouseDown);
        canvasElement.addEventListener("mouseup", onMouseUp);
        canvasElement.addEventListener("mousemove", onMouseMove);
        canvasElement.addEventListener("drop", onDrop);
        canvasElement.addEventListener("dragover", onDragOver);

        return () => {
            canvasElement.removeEventListener("mousedown", onMouseDown);
            canvasElement.removeEventListener("mouseup", onMouseUp);
            canvasElement.removeEventListener("mousemove", onMouseMove);
            canvasElement.removeEventListener("drop", onDrop);
            canvasElement.removeEventListener("dragover", onDragOver);
        };
    }, [deleteModels, wallItems])

    useEffect(() => {
        if (deleteModels) {
            handleMeshMissed(currentWallItem, setSelectedWallItem, setSelectedItemsIndex);
            setSelectedWallItem(null);
            setSelectedItemsIndex(null);
        }
    }, [deleteModels])

    return (
        <>
            {wallItems.map((item: Types.WallItem, index: number) => (
                <group
                    key={index}
                    position={item.position}
                    quaternion={item.quaternion}
                    scale={item.scale}
                >
                    <Csg
                        position={item.csgposition!}
                        scale={item.csgscale!}
                        model={item.model!}
                        hoveredDeletableWallItem={hoveredDeletableWallItem}
                    />
                </group>
            ))}
        </>
    )
}

export default WallItemsGroup;