import { useEffect } from "react";
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import gsap from 'gsap';
import { toast } from 'react-toastify';
import { useSocketStore, useActiveLayer, useWallItems, useFloorItems, useLayers, useUpdateScene, useWalls, useDeletedLines, useNewLines, useZonePoints, useZones } from "../../store/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 { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { retrieveGLTF, storeGLTF } from "../../utils/indexDB/idbUtils";
import { getZonesApi } from "../../services/factoryBuilder/zones/getZonesApi";


export default function SocketResponses({
    floorPlanGroup,
    lines,
    floorGroup,
    floorGroupAisle,
    scene,
    onlyFloorlines,
    AssetConfigurations,
    itemsGroup,
    isTempLoader,
    tempLoader,
    currentLayerPoint,
    floorPlanGroupPoint,
    floorPlanGroupLine,
    zoneGroup,
    dragPointControls
}: any) {

    const { socket } = useSocketStore();
    const { activeLayer, setActiveLayer } = useActiveLayer();
    const { wallItems, setWallItems } = useWallItems();
    const { layers, setLayers } = useLayers();
    const { floorItems, setFloorItems } = useFloorItems();
    const { updateScene, setUpdateScene } = useUpdateScene();
    const { walls, setWalls } = useWalls();
    const { deletedLines, setDeletedLines } = useDeletedLines();
    const { newLines, setNewLines } = useNewLines();
    const { zones, setZones } = useZones();
    const { zonePoints, setZonePoints } = useZonePoints();

    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('cameraUpdateResponse', (data: any) => {
            // console.log('data: ', data);
        })

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

        socket.on('model-asset:response:updates', 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: () => { toast.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/v1/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) {
                    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: () => { toast.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('model-asset:response:updates', (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);
                toast.success("Model Removed!");
            }
        })

        socket.on('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('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);

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

        socket.on('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);

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

        socket.on('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);
                const highestLayer = Math.max(
                    1,
                    lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
                    zonesData.data.reduce((maxLayer: number, zone: any) => Math.max(maxLayer, zone.layer || 0), 0)
                );

                setLayers(highestLayer);

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

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

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

        socket.on('wallItemsDeleteResponse', (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));
                    toast.success("Model Removed!");
                }, 50);
            }
        })

        socket.on('wallItemsUpdateResponse', (data: any) => {
            if (socket.id === data.socketId) {
                return
            }
            if (organization !== data.organization) {
                return
            }
            if (data.message === "wallIitem created") {
                const loader = new GLTFLoader();
                loader.load(AssetConfigurations[data.data.modelname].modelUrl, async (gltf) => {
                    const model = gltf.scene;
                    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,
                        scale: data.data.scale,
                        csgscale: data.data.csgscale,
                        csgposition: data.data.csgposition,
                        position: data.data.position,
                        quaternion: data.data.quaternion
                    };

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

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

                        localStorage.setItem("WallItems", JSON.stringify(WallItemsForStorage));
                        toast.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));
                    toast.success("Model Updated!");

                    return updatedItems;
                });

            }

        })

        return () => {
            socket.off('wallItemsDeleteResponse');
            socket.off('wallItemsUpdateResponse');
        };
    }, [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('Line:response:create', async (data: any) => {
            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);
                const highestLayer = Math.max(
                    1,
                    lines.current.reduce((maxLayer: number, segment: any) => Math.max(maxLayer, segment.layer || 0), 0),
                    zonesData.data.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('Line:response:create');
        };
    }, [socket, activeLayer])

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

        socket.on('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.zoneId === data.data.zoneId ? data.data : zone
                );
                setZones(updatedZones);
                setUpdateScene(true);
            }


        })

        socket.on('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.zoneId !== data.data.zoneId);
                setZones(updatedZones);

                const zoneIndex = zones.findIndex((zone: any) => zone.zoneId === data.data.zoneId);
                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('zone:response:updates');
            socket.off('zone:response:delete');
        };
    }, [socket, zones, zonePoints])

    return (
        <></>
    )
}