import { useEffect } from "react";
import * as THREE from "three";
import gsap from "gsap";
import { GLTF, GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import {
    useSocketStore,
    useActiveLayer,
    useWallItems,
    useFloorItems,
    useLayers,
    useUpdateScene,
    useWalls,
    useDeletedLines,
    useNewLines,
    useZonePoints,
    useZones,
} from "../../../store/builder/store";

import * as Types from "../../../types/world/worldTypes";
import * as CONSTANTS from "../../../types/world/worldConstants";
import TempLoader from "../../builder/geomentries/assets/tempLoader";

// import { setFloorItemApi } from "../../services/factoryBuilder/assest/floorAsset/setFloorItemApi";
import objectLineToArray from "../../builder/geomentries/lines/lineConvertions/objectLineToArray";
import addLineToScene from "../../builder/geomentries/lines/addLineToScene";
import updateLinesPositions from "../../builder/geomentries/lines/updateLinesPositions";
import updateLines from "../../builder/geomentries/lines/updateLines";
import updateDistanceText from "../../builder/geomentries/lines/updateDistanceText";
import updateFloorLines from "../../builder/geomentries/floors/updateFloorLines";
import loadWalls from "../../builder/geomentries/walls/loadWalls";
import RemoveConnectedLines from "../../builder/geomentries/lines/removeConnectedLines";
import Layer2DVisibility from "../../builder/geomentries/layers/layer2DVisibility";
import { retrieveGLTF, storeGLTF } from "../../../utils/indexDB/idbUtils";
import { getZonesApi } from "../../../services/factoryBuilder/zones/getZonesApi";
import { useParams } from "react-router-dom";

export default function SocketResponses({
    floorPlanGroup,
    lines,
    floorGroup,
    floorGroupAisle,
    scene,
    onlyFloorlines,
    itemsGroup,
    isTempLoader,
    tempLoader,
    currentLayerPoint,
    floorPlanGroupPoint,
    floorPlanGroupLine,
    zoneGroup,
    dragPointControls,
}: any) {
    const { socket } = useSocketStore();
    const { activeLayer, setActiveLayer } = useActiveLayer();
    const { wallItems, setWallItems } = useWallItems();
    const { setLayers } = useLayers();
    const { setFloorItems } = useFloorItems();
    const { setUpdateScene } = useUpdateScene();
    const { setWalls } = useWalls();
    const { setDeletedLines } = useDeletedLines();
    const { setNewLines } = useNewLines();
    const { zones, setZones } = useZones();
    const { zonePoints, setZonePoints } = useZonePoints();
    const { projectId } = useParams();

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

        if (!socket) return;

        socket.on("cameraCreateResponse", (data: any) => {
            // console.log('data: ', data);
        });

        socket.on("userConnectRespones", (data: any) => {
            // console.log('data: ', data);
        });

        socket.on("userDisConnectRespones", (data: any) => {
            // console.log('data: ', data);
        });

        socket.on("v1:camera:Response:update", (data: any) => {
            // console.log('data: ', data);
        });

        socket.on("EnvironmentUpdateResponse", (data: any) => {
            // console.log('data: ', data);
        });

        socket.on("v1:model-asset:response:add", async (data: any) => {
            // console.log('data: ', data);
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "Model created successfully") {
                const loader = new GLTFLoader();
                const dracoLoader = new DRACOLoader();

                dracoLoader.setDecoderPath(
                    "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/"
                );
                loader.setDRACOLoader(dracoLoader);
                let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;

                try {
                    isTempLoader.current = true;
                    const cachedModel = THREE.Cache.get(data.data.modelName);
                    let url;
                    if (cachedModel) {
                        // console.log(`Getting ${data.data.modelName} from cache`);
                        const model = cachedModel.scene.clone();
                        model.uuid = data.data.modelUuid;
                        model.userData = {
                            name: data.data.modelName,
                            modelId: data.data.modelfileID,
                            modelUuid: data.data.modelUuid,
                        };
                        model.position.set(
                            ...(data.data.position as [number, number, number])
                        );
                        model.rotation.set(
                            data.data.rotation.x,
                            data.data.rotation.y,
                            data.data.rotation.z
                        );
                        model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);

                        model.traverse((child: any) => {
                            if (child.isMesh) {
                                // Clone the material to ensure changes are independent
                                // child.material = child.material.clone();

                                child.castShadow = true;
                                child.receiveShadow = true;
                            }
                        });

                        itemsGroup.current.add(model);

                        if (tempLoader.current) {
                            tempLoader.current.material.dispose();
                            tempLoader.current.geometry.dispose();
                            itemsGroup.current.remove(tempLoader.current);
                            tempLoader.current = undefined;
                        }

                        const newFloorItem: Types.FloorItemType = {
                            modelUuid: data.data.modelUuid,
                            modelName: data.data.modelName,
                            modelfileID: data.data.modelfileID,
                            position: [...(data.data.position as [number, number, number])],
                            rotation: {
                                x: model.rotation.x,
                                y: model.rotation.y,
                                z: model.rotation.z,
                            },
                            isLocked: data.data.isLocked,
                            isVisible: data.data.isVisible,
                        };

                        setFloorItems((prevItems: any) => {
                            const updatedItems = [...(prevItems || []), newFloorItem];
                            localStorage.setItem("FloorItems", JSON.stringify(updatedItems));
                            return updatedItems;
                        });

                        gsap.to(model.position, {
                            y: data.data.position[1],
                            duration: 1.5,
                            ease: "power2.out",
                        });
                        gsap.to(model.scale, {
                            x: 1,
                            y: 1,
                            z: 1,
                            duration: 1.5,
                            ease: "power2.out",
                            onComplete: () => {
                                echo.success("Model Added!");
                            },
                        });
                    } else {
                        const indexedDBModel = await retrieveGLTF(data.data.modelName);
                        if (indexedDBModel) {
                            // console.log(`Getting ${data.data.modelName} from IndexedDB`);
                            url = URL.createObjectURL(indexedDBModel);
                        } else {
                            // console.log(`Getting ${data.data.modelName} from Backend`);
                            url = `${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`;
                            const modelBlob = await fetch(url).then((res) => res.blob());
                            await storeGLTF(data.data.modelfileID, modelBlob);
                        }
                    }

                    if (url) {
                        loadModel(url);
                    }
                } catch (error) {
                    echo.error("Failed to update responce");
                    console.error("Error fetching asset model:", error);
                }

                function loadModel(url: string) {
                    loader.load(
                        url,
                        (gltf) => {
                            URL.revokeObjectURL(url);
                            THREE.Cache.remove(url);
                            const model = gltf.scene;
                            model.uuid = data.data.modelUuid;
                            model.userData = {
                                name: data.data.modelName,
                                modelId: data.data.modelfileID,
                                modelUuid: data.data.modelUuid,
                            };
                            model.position.set(
                                ...(data.data.position as [number, number, number])
                            );
                            model.rotation.set(
                                data.data.rotation.x,
                                data.data.rotation.y,
                                data.data.rotation.z
                            );
                            model.scale.set(...CONSTANTS.assetConfig.defaultScaleBeforeGsap);

                            model.traverse((child: any) => {
                                if (child.isMesh) {
                                    // Clone the material to ensure changes are independent
                                    // child.material = child.material.clone();

                                    child.castShadow = true;
                                    child.receiveShadow = true;
                                }
                            });

                            itemsGroup.current.add(model);

                            if (tempLoader.current) {
                                tempLoader.current.material.dispose();
                                tempLoader.current.geometry.dispose();
                                itemsGroup.current.remove(tempLoader.current);
                                tempLoader.current = undefined;
                            }

                            const newFloorItem: Types.FloorItemType = {
                                modelUuid: data.data.modelUuid,
                                modelName: data.data.modelName,
                                modelfileID: data.data.modelfileID,
                                position: [...(data.data.position as [number, number, number])],
                                rotation: {
                                    x: model.rotation.x,
                                    y: model.rotation.y,
                                    z: model.rotation.z,
                                },
                                isLocked: data.data.isLocked,
                                isVisible: data.data.isVisible,
                            };

                            setFloorItems((prevItems: any) => {
                                const updatedItems = [...(prevItems || []), newFloorItem];
                                localStorage.setItem(
                                    "FloorItems",
                                    JSON.stringify(updatedItems)
                                );
                                return updatedItems;
                            });

                            gsap.to(model.position, {
                                y: data.data.position[1],
                                duration: 1.5,
                                ease: "power2.out",
                            });
                            gsap.to(model.scale, {
                                x: 1,
                                y: 1,
                                z: 1,
                                duration: 1.5,
                                ease: "power2.out",
                                onComplete: () => {
                                    echo.success("Model Added!");
                                },
                            });

                            THREE.Cache.add(data.data.modelName, gltf);
                        },
                        () => {
                            TempLoader(
                                new THREE.Vector3(...data.data.position),
                                isTempLoader,
                                tempLoader,
                                itemsGroup
                            );
                        }
                    );
                }
            } else if (data.message === "Model updated successfully") {
                itemsGroup.current?.children.forEach((item: THREE.Group) => {
                    if (item.uuid === data.data.modelUuid) {
                        item.position.set(
                            ...(data.data.position as [number, number, number])
                        );
                        item.rotation.set(
                            data.data.rotation.x,
                            data.data.rotation.y,
                            data.data.rotation.z
                        );
                    }
                });

                setFloorItems((prevItems: Types.FloorItems) => {
                    if (!prevItems) {
                        return;
                    }
                    let updatedItem: any = null;
                    const updatedItems = prevItems.map((item) => {
                        if (item.modelUuid === data.data.modelUuid) {
                            updatedItem = {
                                ...item,
                                position: [...data.data.position] as [number, number, number],
                                rotation: {
                                    x: data.data.rotation.x,
                                    y: data.data.rotation.y,
                                    z: data.data.rotation.z,
                                },
                            };
                            return updatedItem;
                        }
                        return item;
                    });
                    return updatedItems;
                });
            }
        });

        socket.on("v1:model-asset:response:add", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "Model deleted successfully") {
                const deletedUUID = data.data.modelUuid;
                let items = JSON.parse(localStorage.getItem("FloorItems")!);

                const updatedItems = items.filter(
                    (item: { modelUuid: string }) => item.modelUuid !== deletedUUID
                );

                const storedItems = JSON.parse(
                    localStorage.getItem("FloorItems") || "[]"
                );
                const updatedStoredItems = storedItems.filter(
                    (item: { modelUuid: string }) => item.modelUuid !== deletedUUID
                );
                localStorage.setItem("FloorItems", JSON.stringify(updatedStoredItems));

                itemsGroup.current.children.forEach((item: any) => {
                    if (item.uuid === deletedUUID) {
                        itemsGroup.current.remove(item);
                    }
                });
                setFloorItems(updatedItems);
                echo.success("Model Removed!");
            }
        });

        socket.on("v1:Line:response:update", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "line updated") {
                const DraggedUUID = data.data.uuid;
                const DraggedPosition = new THREE.Vector3(
                    data.data.position.x,
                    data.data.position.y,
                    data.data.position.z
                );

                const point = floorPlanGroupPoint.current.getObjectByProperty(
                    "uuid",
                    DraggedUUID
                );
                point.position.set(
                    DraggedPosition.x,
                    DraggedPosition.y,
                    DraggedPosition.z
                );
                const affectedLines = updateLinesPositions(
                    { uuid: DraggedUUID, position: DraggedPosition },
                    lines
                );

                updateLines(floorPlanGroupLine, affectedLines);
                updateDistanceText(scene, floorPlanGroupLine, affectedLines);
                updateFloorLines(onlyFloorlines, {
                    uuid: DraggedUUID,
                    position: DraggedPosition,
                });

                loadWalls(lines, setWalls);
                setUpdateScene(true);
            }
        });

        socket.on("v1:Line:response:delete", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "line deleted") {
                const line = objectLineToArray(data.data);
                const linePoints = line;
                const connectedpoints = [linePoints[0][1], linePoints[1][1]];

                onlyFloorlines.current = onlyFloorlines.current
                    .map((floorline: any) =>
                        floorline.filter(
                            (line: any) =>
                                line[0][1] !== connectedpoints[0] &&
                                line[1][1] !== connectedpoints[1]
                        )
                    )
                    .filter((floorline: any) => floorline.length > 0);

                const removedLine = lines.current.find(
                    (item: any) =>
                        (item[0][1] === linePoints[0][1] &&
                            item[1][1] === linePoints[1][1]) ||
                        (item[0][1] === linePoints[1][1] && item[1][1] === linePoints[0][1])
                );
                lines.current = lines.current.filter(
                    (item: any) => item !== removedLine
                );

                floorPlanGroupLine.current.children.forEach((line: any) => {
                    const linePoints = line.userData.linePoints as [
                        number,
                        string,
                        number
                    ][];
                    const uuid1 = linePoints[0][1];
                    const uuid2 = linePoints[1][1];

                    if (
                        (uuid1 === connectedpoints[0] && uuid2 === connectedpoints[1]) ||
                        (uuid1 === connectedpoints[1] && uuid2 === connectedpoints[0])
                    ) {
                        line.material.dispose();
                        line.geometry.dispose();
                        floorPlanGroupLine.current.remove(line);
                        setDeletedLines([line.userData.linePoints]);
                    }
                });

                connectedpoints.forEach((pointUUID) => {
                    let isConnected = false;
                    floorPlanGroupLine.current.children.forEach((line: any) => {
                        const linePoints = line.userData.linePoints;
                        const uuid1 = linePoints[0][1];
                        const uuid2 = linePoints[1][1];
                        if (uuid1 === pointUUID || uuid2 === pointUUID) {
                            isConnected = true;
                        }
                    });

                    if (!isConnected) {
                        floorPlanGroupPoint.current.children.forEach((point: any) => {
                            if (point.uuid === pointUUID) {
                                point.material.dispose();
                                point.geometry.dispose();
                                floorPlanGroupPoint.current.remove(point);
                            }
                        });
                    }
                });

                loadWalls(lines, setWalls);
                setUpdateScene(true);

                echo.success("Line Removed!");
            }
        });

        socket.on("v1:Line:response:delete:point", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "point deleted") {
                const point = floorPlanGroupPoint.current?.getObjectByProperty(
                    "uuid",
                    data.data
                );
                point.material.dispose();
                point.geometry.dispose();
                floorPlanGroupPoint.current.remove(point);

                onlyFloorlines.current = onlyFloorlines.current
                    .map((floorline: any) =>
                        floorline.filter(
                            (line: any) =>
                                line[0][1] !== data.data && line[1][1] !== data.data
                        )
                    )
                    .filter((floorline: any) => floorline.length > 0);

                RemoveConnectedLines(
                    data.data,
                    floorPlanGroupLine,
                    floorPlanGroupPoint,
                    setDeletedLines,
                    lines
                );

                loadWalls(lines, setWalls);
                setUpdateScene(true);

                echo.success("Point Removed!");
            }
        });

        socket.on("v1:Line:response:delete:layer", async (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "layer deleted") {
                setActiveLayer(1);
                const removedLayer = data.data;
                const removedLines: Types.Lines = lines.current.filter(
                    (line: any) => line[0][2] === removedLayer
                );

                //////////  Remove Points and lines from the removed layer  //////////

                removedLines.forEach(async (line) => {
                    line.forEach(async (removedPoint) => {
                        const removableLines: THREE.Mesh[] = [];
                        const connectedpoints: string[] = [];

                        floorPlanGroupLine.current.children.forEach((line: any) => {
                            const linePoints = line.userData.linePoints as [
                                number,
                                string,
                                number
                            ][];
                            const uuid1 = linePoints[0][1];
                            const uuid2 = linePoints[1][1];

                            if (uuid1 === removedPoint[1] || uuid2 === removedPoint[1]) {
                                connectedpoints.push(uuid1 === removedPoint[1] ? uuid2 : uuid1);
                                removableLines.push(line as THREE.Mesh);
                            }
                        });

                        if (removableLines.length > 0) {
                            removableLines.forEach((line: any) => {
                                lines.current = lines.current.filter(
                                    (item: any) =>
                                        JSON.stringify(item) !==
                                        JSON.stringify(line.userData.linePoints)
                                );
                                line.material.dispose();
                                line.geometry.dispose();
                                floorPlanGroupLine.current.remove(line);
                            });
                        }

                        const point = floorPlanGroupPoint.current.getObjectByProperty(
                            "uuid",
                            removedPoint[1]
                        );
                        if (point) {
                            point.material.dispose();
                            point.geometry.dispose();
                            floorPlanGroupPoint.current.remove(point);
                        }
                    });
                });

                //////////  Update the remaining lines layer values in the userData and in lines.current  //////////

                let remaining = lines.current.filter(
                    (line: any) => line[0][2] !== removedLayer
                );
                let updatedLines: Types.Lines = [];
                remaining.forEach((line: any) => {
                    let newLines = JSON.parse(JSON.stringify(line));
                    if (newLines[0][2] > removedLayer) {
                        newLines[0][2] -= 1;
                        newLines[1][2] -= 1;
                    }

                    const matchingLine = floorPlanGroupLine.current.children.find(
                        (l: any) =>
                            l.userData.linePoints[0][1] === line[0][1] &&
                            l.userData.linePoints[1][1] === line[1][1]
                    );
                    if (matchingLine) {
                        const updatedUserData = JSON.parse(
                            JSON.stringify(matchingLine.userData)
                        );
                        updatedUserData.linePoints[0][2] = newLines[0][2];
                        updatedUserData.linePoints[1][2] = newLines[1][2];
                        matchingLine.userData = updatedUserData;
                    }
                    updatedLines.push(newLines);
                });

                lines.current = updatedLines;
                localStorage.setItem("Lines", JSON.stringify(lines.current));

                //////////  Also remove OnlyFloorLines and update it in localstorage  //////////

                onlyFloorlines.current = onlyFloorlines.current.filter((floor: any) => {
                    return floor[0][0][2] !== removedLayer;
                });
                const meshToRemove = floorGroup.current?.children.find(
                    (mesh: any) => mesh.name === `Only_Floor_Line_${removedLayer}`
                );
                if (meshToRemove) {
                    meshToRemove.geometry.dispose();
                    meshToRemove.material.dispose();
                    floorGroup.current?.remove(meshToRemove);
                }

                const zonesData = await getZonesApi(organization,projectId);
                const highestLayer = Math.max(
                    1,
                    lines.current.reduce(
                        (maxLayer: number, segment: any) =>
                            Math.max(maxLayer, segment.layer || 0),
                        0
                    ),
                    zonesData.reduce(
                        (maxLayer: number, zone: any) =>
                            Math.max(maxLayer, zone.layer || 0),
                        0
                    )
                );

                setLayers(highestLayer);

                loadWalls(lines, setWalls);
                setUpdateScene(true);

                echo.success("Layer Removed!");
            }
        });
    }, [socket]);

    useEffect(() => {
        if (!socket) return;
        const email = localStorage.getItem("email");
        const organization = email!.split("@")[1].split(".")[0];
        let url_Backend_dwinzo = `http://${process.env.REACT_APP_SERVER_MARKETPLACE_URL}`;

        socket.on("v1:wallItem:Response:Delete", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "wallitem deleted") {
                const deletedUUID = data.data.modelUuid;
                let WallItemsRef = wallItems;
                const Items = WallItemsRef.filter((item: any) => item.model?.uuid !== deletedUUID);

                setWallItems([]);
                setTimeout(async () => {
                    WallItemsRef = Items;
                    setWallItems(WallItemsRef);
                    const WallItemsForStorage = WallItemsRef.map((item: any) => {
                        const { model, ...rest } = item;
                        return {
                            ...rest,
                            modelUuid: model?.uuid,
                        };
                    });

                    localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
                    echo.success("Model Removed!");
                }, 50);
            }
        });

        socket.on("v1:wallItems:Response:Update", (data: any) => {
            // console.log('data: ', data);
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "wallIitem created") {
                const loader = new GLTFLoader();
                const dracoLoader = new DRACOLoader();

                dracoLoader.setDecoderPath('https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/libs/draco/gltf/');
                loader.setDRACOLoader(dracoLoader);

                // Check THREE.js cache first
                const cachedModel = THREE.Cache.get(data.data.modelfileID);
                if (cachedModel) {
                    handleModelLoad(cachedModel);
                    return;
                }

                // Check IndexedDB cache
                retrieveGLTF(data.data.modelfileID).then((cachedModelBlob) => {
                    if (cachedModelBlob) {
                        const blobUrl = URL.createObjectURL(cachedModelBlob);
                        loader.load(blobUrl, (gltf) => {
                            URL.revokeObjectURL(blobUrl);
                            THREE.Cache.remove(blobUrl);
                            THREE.Cache.add(data.data.modelfileID, gltf);
                            handleModelLoad(gltf);
                        });
                        return;
                    }
                })

                // Load from backend if not in any cache
                loader.load(`${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`, async (gltf) => {
                    try {
                        const modelBlob = await fetch(`${url_Backend_dwinzo}/api/v2/AssetFile/${data.data.modelfileID}`).then((res) => res.blob());
                        await storeGLTF(data.data.modelfileID, modelBlob);
                        THREE.Cache.add(data.data.modelfileID, gltf);
                        await handleModelLoad(gltf);
                    } catch (error) {
                        console.error('Failed to cache model:', error);
                        handleModelLoad(gltf);
                    }
                });

                async function handleModelLoad(gltf: GLTF) {
                    const model = gltf.scene.clone();
                    model.uuid = data.data.modelUuid;

                    model.children[0].children.forEach((child) => {
                        if (child.name !== "CSG_REF") {
                            child.castShadow = true;
                            child.receiveShadow = true;
                        }
                    });

                    const newWallItem = {
                        type: data.data.type,
                        model: model,
                        modelName: data.data.modelName,
                        modelfileID: data.data.modelfileID,
                        scale: data.data.scale,
                        csgscale: data.data.csgscale,
                        csgposition: data.data.csgposition,
                        position: data.data.position,
                        quaternion: data.data.quaternion,
                    };

                    setWallItems((prevItems: Types.wallItems) => {
                        const updatedItems = [...prevItems, newWallItem];

                        const WallItemsForStorage = updatedItems.map(item => {
                            const { model, ...rest } = item;
                            return {
                                ...rest,
                                modelUuid: model?.uuid,
                            };
                        });

                        localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
                        echo.success("Model Added!");
                        return updatedItems;
                    });
                }

            } else if (data.message === "wallIitem updated") {
                const updatedUUID = data.data.modelUuid;

                setWallItems((prevItems: any) => {
                    const updatedItems = prevItems.map((item: any) => {
                        if (item.model.uuid === updatedUUID) {
                            return {
                                ...item,
                                position: data.data.position,
                                quaternion: data.data.quaternion,
                                scale: data.data.scale,
                                csgscale: data.data.csgscale,
                                csgposition: data.data.csgposition,
                            };
                        }
                        return item;
                    });

                    const WallItemsForStorage = updatedItems.map((item: any) => {
                        const { model, ...rest } = item;
                        return {
                            ...rest,
                            modelUuid: model?.uuid,
                        };
                    });

                    localStorage.setItem(
                        "WallItems",
                        JSON.stringify(WallItemsForStorage)
                    );
                    echo.success("Model Updated!");

                    return updatedItems;
                });
            }
        });

        return () => {
            socket.off("v1:wallItem:Response:Delete");
            socket.off("v1:wallItems:Response:Update");
        };
    }, [wallItems]);

    function getPointColor(lineType: string | undefined): string {
        switch (lineType) {
            case CONSTANTS.lineConfig.wallName:
                return CONSTANTS.pointConfig.wallOuterColor;
            case CONSTANTS.lineConfig.floorName:
                return CONSTANTS.pointConfig.floorOuterColor;
            case CONSTANTS.lineConfig.aisleName:
                return CONSTANTS.pointConfig.aisleOuterColor;
            default:
                return CONSTANTS.pointConfig.defaultOuterColor;
        }
    }

    function getLineColor(lineType: string | undefined): string {
        switch (lineType) {
            case CONSTANTS.lineConfig.wallName:
                return CONSTANTS.lineConfig.wallColor;
            case CONSTANTS.lineConfig.floorName:
                return CONSTANTS.lineConfig.floorColor;
            case CONSTANTS.lineConfig.aisleName:
                return CONSTANTS.lineConfig.aisleColor;
            default:
                return CONSTANTS.lineConfig.defaultColor;
        }
    }

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

        socket.on("v1:Line:response:create", async (data: any) => {
            // console.log('data: ', data);
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "line create") {
                const line: Types.Line = objectLineToArray(data.data);
                const type = line[0][3];
                const pointColour = getPointColor(type);
                const lineColour = getLineColor(type);
                setNewLines([line]);

                line.forEach((line) => {
                    const existingPoint =
                        floorPlanGroupPoint.current?.getObjectByProperty("uuid", line[1]);
                    if (existingPoint) {
                        return;
                    }
                    const geometry = new THREE.BoxGeometry(
                        ...CONSTANTS.pointConfig.boxScale
                    );
                    const material = new THREE.ShaderMaterial({
                        uniforms: {
                            uColor: { value: new THREE.Color(pointColour) }, // Blue color for the border
                            uInnerColor: {
                                value: new THREE.Color(CONSTANTS.pointConfig.defaultInnerColor),
                            }, // White color for the inner square
                        },
                        vertexShader: `
                                      varying vec2 vUv;
                                  
                                      void main() {
                                        vUv = uv;
                                        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
                                      }
                                    `,
                        fragmentShader: `
                                      varying vec2 vUv;
                                      uniform vec3 uColor;
                                      uniform vec3 uInnerColor;
                                  
                                      void main() {
                                        // Define the size of the white square as a proportion of the face
                                        float borderThickness = 0.2; // Adjust this value for border thickness
                                        if (vUv.x > borderThickness && vUv.x < 1.0 - borderThickness && 
                                            vUv.y > borderThickness && vUv.y < 1.0 - borderThickness) {
                                          gl_FragColor = vec4(uInnerColor, 1.0); // White inner square
                                        } else {
                                          gl_FragColor = vec4(uColor, 1.0); // Blue border
                                        }
                                      }
                                    `,
                    });
                    const point = new THREE.Mesh(geometry, material);
                    point.name = "point";
                    point.uuid = line[1];
                    point.userData = { type: type, color: pointColour };
                    point.position.set(line[0].x, line[0].y, line[0].z);
                    currentLayerPoint.current.push(point);

                    floorPlanGroupPoint.current?.add(point);
                });
                if (dragPointControls.current) {
                    dragPointControls.current!.objects = currentLayerPoint.current;
                }
                addLineToScene(
                    new THREE.Vector3(line[0][0].x, line[0][0].y, line[0][0].z),
                    new THREE.Vector3(line[1][0].x, line[1][0].y, line[1][0].z),
                    lineColour,
                    line,
                    floorPlanGroupLine
                );
                lines.current.push(line);

                const zonesData = await getZonesApi(organization,projectId);
                const highestLayer = Math.max(
                    1,
                    lines.current.reduce(
                        (maxLayer: number, segment: any) =>
                            Math.max(maxLayer, segment.layer || 0),
                        0
                    ),
                    zonesData.reduce(
                        (maxLayer: number, zone: any) =>
                            Math.max(maxLayer, zone.layer || 0),
                        0
                    )
                );

                setLayers(highestLayer);

                Layer2DVisibility(
                    activeLayer,
                    floorPlanGroup,
                    floorPlanGroupLine,
                    floorPlanGroupPoint,
                    currentLayerPoint,
                    dragPointControls
                );

                loadWalls(lines, setWalls);
                setUpdateScene(true);
            }
        });

        return () => {
            socket.off("v1:Line:response:create");
        };
    }, [socket, activeLayer]);

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

        socket.on("v1:zone:response:updates", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }

            if (data.message === "zone created") {
                const pointsArray: [number, number, number][] = data.data.points;
                const vector3Array = pointsArray.map(
                    ([x, y, z]) => new THREE.Vector3(x, y, z)
                );
                const newZones = [...zones, data.data];
                setZones(newZones);
                const updatedZonePoints = [...zonePoints, ...vector3Array];
                setZonePoints(updatedZonePoints);

                const highestLayer = Math.max(
                    1,
                    lines.current.reduce(
                        (maxLayer: number, segment: any) =>
                            Math.max(maxLayer, segment.layer || 0),
                        0
                    ),
                    newZones.reduce(
                        (maxLayer: number, zone: any) =>
                            Math.max(maxLayer, zone.layer || 0),
                        0
                    )
                );

                setLayers(highestLayer);
                setUpdateScene(true);
            }

            if (data.message === "zone updated") {
                const updatedZones = zones.map((zone: any) =>
                    zone.zoneUuid === data.data.zoneUuid ? data.data : zone
                );
                setZones(updatedZones);
                setUpdateScene(true);
            }
        });

        socket.on("v1:zone:response:delete", (data: any) => {
            if (socket.id === data.socketId) {
                return;
            }
            if (organization !== data.organization) {
                return;
            }
            if (data.message === "zone deleted") {
                const updatedZones = zones.filter(
                    (zone: any) => zone.zoneUuid !== data.data.zoneUuid
                );
                setZones(updatedZones);

                const zoneIndex = zones.findIndex(
                    (zone: any) => zone.zoneUuid === data.data.zoneUuid
                );
                if (zoneIndex !== -1) {
                    const updatedzonePoints = zonePoints.filter(
                        (_: any, index: any) =>
                            index < zoneIndex * 4 || index >= zoneIndex * 4 + 4
                    );
                    setZonePoints(updatedzonePoints);
                }

                const highestLayer = Math.max(
                    1,
                    lines.current.reduce(
                        (maxLayer: number, segment: any) =>
                            Math.max(maxLayer, segment.layer || 0),
                        0
                    ),
                    updatedZones.reduce(
                        (maxLayer: number, zone: any) =>
                            Math.max(maxLayer, zone.layer || 0),
                        0
                    )
                );

                setLayers(highestLayer);
                setUpdateScene(true);
            }
        });

        return () => {
            socket.off("v1:zone:response:updates");
            socket.off("v1:zone:response:delete");
        };
    }, [socket, zones, zonePoints]);

    return <></>;
}
