import { useParams } from "react-router-dom";
import React, { useState, useRef, useEffect } from "react";
import { dataModelManager } from "./data/dataModel";
import ControlPanel from "./ControlPanel";
import SwapModal from "./SwapModal";
import { Block } from "../../types/exportedTypes";
import DataModelPanel from "./components/models/DataModelPanel";
import AnalyzerManager from "./AnalyzerManager";

import { useSceneContext } from "../../modules/scene/sceneContext";
import useModuleStore from "../../store/ui/useModuleStore";
import { usePlayButtonStore } from "../../store/ui/usePlayButtonStore";
import { calculateMinBlockSize } from "./functions/block/calculateMinBlockSize";
import { handleElementDragStart, handleElementResizeStart, handleBlockResizeStart, handleSwapStart, handleSwapTarget, handleBlockClick, handleElementClick } from "./functions/eventHandlers";
import BlockGrid from "./components/block/BlockGrid";
import BlockEditor from "./components/block/BlockEditor";
import ElementEditor from "./components/element/ElementEditor";
import useCallBackOnKey from "../../utils/hooks/useCallBackOnKey";
import { handleBlockDragStart } from "./functions/block/handleBlockDragStart";

import { getDashBoardBlocksApi } from "../../services/visulization/dashBoard/getDashBoardBlocks";
import { upsetDashBoardBlocksApi } from "../../services/visulization/dashBoard/upsertDashBoardBlocks";
import { deleteDashBoardBlocksApi } from "../../services/visulization/dashBoard/deleteDashBoardBlocks";

const DashboardEditor: React.FC = () => {
    const { simulationDashBoardStore, versionStore } = useSceneContext();
    const { selectedVersion } = versionStore();
    const { projectId } = useParams();
    const { activeModule } = useModuleStore();
    const { isPlaying } = usePlayButtonStore();
    const {
        blocks,
        selectedBlock,
        setSelectedBlock,
        selectedElement,
        setSelectedElement,
        addBlock,
        setBlocks,
        removeBlock,
        removeElement,
        getBlockById,
        updateBlock,
        // Peek methods
        peekAddBlock,
        peekRemoveBlock,
        peekAddElement,
        peekRemoveElement,
        peekUpdateBlockStyle,
        peekUpdateBlockSize,
        peekUpdateBlockPosition,
        peekUpdateBlockPositionType,
        peekUpdateBlockZIndex,
        peekUpdateElementStyle,
        peekUpdateElementSize,
        peekUpdateElementPosition,
        peekUpdateElementPositionType,
        peekUpdateElementZIndex,
        peekUpdateElementData,
        peekUpdateGraphData,
        peekUpdateGraphTitle,
        peekUpdateGraphType,
        peekUpdateDataType,
        peekUpdateCommonValue,
        peekUpdateDataValue,
        peekUpdateDataSource,
        peekSwapElements,
    } = simulationDashBoardStore();

    const [editMode, setEditMode] = useState(false);
    const [draggingElement, setDraggingElement] = useState<string | null>(null);
    const [resizingElement, setResizingElement] = useState<string | null>(null);
    const [resizingBlock, setResizingBlock] = useState<string | null>(null);
    const [resizeStart, setResizeStart] = useState<{
        x: number;
        y: number;
        width: number;
        height: number;
    } | null>(null);
    const [showSwapUI, setShowSwapUI] = useState(false);
    const [swapSource, setSwapSource] = useState<string | null>(null);
    const [dataModel, setDataModel] = useState<DataModel>(dataModelManager.getDataSnapshot());
    const [showDataModelPanel, setShowDataModelPanel] = useState(false);
    const [showElementDropdown, setShowElementDropdown] = useState<string | null>(null);
    const [draggingBlock, setDraggingBlock] = useState<string | null>(null);
    const [elementDragOffset, setElementDragOffset] = useState<Position>({ x: 0, y: 0 });
    const [blockDragOffset, setBlockDragOffset] = useState<Position>({ x: 0, y: 0 });

    const editorRef = useRef<HTMLDivElement>(null);
    const blockEditorRef = useRef<HTMLDivElement>(null);
    const elementEditorRef = useRef<HTMLDivElement>(null);
    const dropdownRef = useRef<HTMLDivElement>(null);
    const blockRef = useRef<HTMLDivElement>(null);

    const currentBlock = blocks.find((b) => b.blockUuid === selectedBlock);
    const currentElement = currentBlock?.elements.find((el) => el.elementUuid === selectedElement);

    // Helper function to send updates to backend - only sends the specific block that changed
    const updateBackend = async (updatedBlock: Block) => {
        if (!projectId || !selectedVersion) return;

        try {
            const response = await upsetDashBoardBlocksApi({
                projectId,
                versionId: selectedVersion.versionId,
                blocks: [updatedBlock], // Send only the updated block
            });

            if (response.data?.blocks) {
                // Update only the blocks that have success messages
                response.data.blocks.forEach((responseBlock: any) => {
                    if (responseBlock.message === "Block updated successfully") {
                        // Update the specific block in the store
                        const { message, elements, ...blockData } = responseBlock;

                        // Process elements to remove their messages
                        const cleanedElements =
                            elements?.map((el: any) => {
                                const { message: elementMessage, ...elementData } = el;
                                return elementData;
                            }) || [];

                        updateBlock(responseBlock.blockUuid, {
                            ...blockData,
                            elements: cleanedElements,
                        });
                    } else if (responseBlock.message === "Block created successfully") {
                        addBlock(responseBlock);
                    }
                });
            }
        } catch (error) {
            console.error("Failed to update backend:", error);
        }
    };

    // Helper function to get a specific block from peeked blocks
    const getBlockFromPeekedBlocks = (peekedBlocks: Block[], blockId: string): Block | undefined => {
        return peekedBlocks.find((b) => b.blockUuid === blockId);
    };

    useEffect(() => {
        if (!projectId || !selectedVersion) return;
        getDashBoardBlocksApi(projectId, selectedVersion.versionId).then((data) => {
            if (data.data?.blocks) {
                setBlocks(data.data.blocks);
            }
        });
    }, [projectId, selectedVersion]);

    useCallBackOnKey(
        () => {
            if (!projectId || !selectedVersion) return;
            // For Ctrl+S, send all blocks
            upsetDashBoardBlocksApi({
                projectId,
                versionId: selectedVersion.versionId,
                blocks: blocks,
            });
        },
        "Ctrl+S",
        { dependencies: [blocks, projectId, selectedVersion], noRepeat: true, allowOnInput: true }
    );

    // Subscribe to data model changes
    useEffect(() => {
        const handleDataChange = (): void => {
            setDataModel(dataModelManager.getDataSnapshot());
        };

        const keys = dataModelManager.getAvailableKeys();
        const subscriptions: Array<[string, () => void]> = [];

        for (const key of keys) {
            const callback = () => handleDataChange();
            dataModelManager.subscribe(key, callback);
            subscriptions.push([key, callback]);
        }

        const interval = setInterval(() => {
            const currentKeys = dataModelManager.getAvailableKeys();
            const newKeys = currentKeys.filter((key) => !keys.includes(key));

            for (const key of newKeys) {
                const callback = () => handleDataChange();
                dataModelManager.subscribe(key, callback);
                subscriptions.push([key, callback]);
            }
        }, 1000);

        return () => {
            for (const [key, callback] of subscriptions) {
                dataModelManager.unsubscribe(key, callback);
            }
            clearInterval(interval);
        };
    }, []);

    // Click outside handler
    useEffect(() => {
        const handleClickOutside = (event: MouseEvent): void => {
            const target = event.target as Node;

            const isInsideBlockEditor = blockEditorRef.current?.contains(target);
            const isInsideElementEditor = elementEditorRef.current?.contains(target);
            const isInsideDropdown = dropdownRef.current?.contains(target);
            const isInsideEditor = editorRef.current?.contains(target);

            if (!isInsideEditor) {
                setSelectedBlock(null);
                setSelectedElement(null);
                setShowSwapUI(false);
                return;
            }

            if (isInsideEditor && !isInsideBlockEditor && !isInsideElementEditor && !isInsideDropdown) {
                const clickedElement = event.target as HTMLElement;
                const isBlock = clickedElement.closest("[data-block-id]");
                const isElement = clickedElement.closest("[data-element-id]");
                const isButton = clickedElement.closest("button");
                const isResizeHandle = clickedElement.closest(".resize-handle");

                if (!isBlock && !isElement && !isButton && !isResizeHandle) {
                    setSelectedBlock(null);
                    setSelectedElement(null);
                    setShowSwapUI(false);
                    setShowElementDropdown(null);
                }
            }
        };

        // document.addEventListener("mousedown", handleClickOutside);
        return () => {
            document.removeEventListener("mousedown", handleClickOutside);
        };
    }, [selectedBlock, selectedElement]);

    // Drag and drop handler
    useEffect(() => {
        const handleMouseMove = (e: MouseEvent): void => {
            // Element dragging - direct DOM manipulation
            if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
                const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
                const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;

                if (blockElement && elementToDrag) {
                    const blockRect = blockElement.getBoundingClientRect();
                    const newX = e.clientX - blockRect.left - elementDragOffset.x;
                    const newY = e.clientY - blockRect.top - elementDragOffset.y;

                    // Direct DOM manipulation
                    elementToDrag.style.left = `${Math.max(0, Math.min(blockRect.width - 50, newX))}px`;
                    elementToDrag.style.top = `${Math.max(0, Math.min(blockRect.height - 30, newY))}px`;
                }
            }

            // Block dragging - direct DOM manipulation
            if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
                const editorElement = editorRef.current;
                const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;

                if (editorElement && blockToDrag) {
                    const editorRect = editorElement.getBoundingClientRect();
                    const newX = e.clientX - editorRect.left - blockDragOffset.x;
                    const newY = e.clientY - editorRect.top - blockDragOffset.y;

                    // Direct DOM manipulation
                    blockToDrag.style.left = `${Math.max(0, Math.min(editorRect.width - (currentBlock.size?.width || 400), newX))}px`;
                    blockToDrag.style.top = `${Math.max(0, Math.min(editorRect.height - (currentBlock.size?.height || 300), newY))}px`;
                }
            }

            // Resizing - direct DOM manipulation
            if ((resizingElement || resizingBlock) && resizeStart) {
                if (resizingElement && selectedBlock) {
                    const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
                    if (elementToResize) {
                        const deltaX = e.clientX - resizeStart.x;
                        const deltaY = e.clientY - resizeStart.y;

                        const newWidth = Math.max(100, resizeStart.width + deltaX);
                        const newHeight = Math.max(50, resizeStart.height + deltaY);

                        // Direct DOM manipulation
                        elementToResize.style.width = `${newWidth}px`;
                        elementToResize.style.height = `${newHeight}px`;
                    }
                } else if (resizingBlock) {
                    const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
                    if (blockToResize) {
                        const deltaX = e.clientX - resizeStart.x;
                        const deltaY = e.clientY - resizeStart.y;

                        const currentBlock = blocks.find((b) => b.blockUuid === resizingBlock);
                        const minSize = currentBlock ? calculateMinBlockSize(currentBlock) : { width: 100, height: 50 };

                        const newWidth = Math.max(minSize.width, resizeStart.width + deltaX);
                        const newHeight = Math.max(minSize.height, resizeStart.height + deltaY);

                        // Direct DOM manipulation
                        blockToResize.style.width = `${newWidth}px`;
                        blockToResize.style.height = `${newHeight}px`;
                    }
                }
            }
        };

        const handleMouseUp = async (): Promise<void> => {
            // Update backend using peek methods, then update state from response
            if (draggingElement && selectedBlock && currentElement?.positionType === "absolute") {
                const blockElement = document.querySelector(`[data-block-id="${selectedBlock}"]`) as HTMLElement;
                const elementToDrag = document.querySelector(`[data-element-id="${draggingElement}"]`) as HTMLElement;

                if (blockElement && elementToDrag) {
                    const computedStyle = window.getComputedStyle(elementToDrag);
                    const x = parseFloat(computedStyle.left);
                    const y = parseFloat(computedStyle.top);

                    // Use peek to get updated blocks and send only the affected block to backend
                    const updatedBlocks = peekUpdateElementPosition(selectedBlock, draggingElement, { x, y });
                    const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, selectedBlock);
                    if (updatedBlock) {
                        await updateBackend(updatedBlock);
                    }
                }
            }

            // Update backend for block drag
            if (draggingBlock && currentBlock?.positionType && (currentBlock.positionType === "absolute" || currentBlock.positionType === "fixed")) {
                const blockToDrag = document.querySelector(`[data-block-id="${draggingBlock}"]`) as HTMLElement;

                if (blockToDrag) {
                    const computedStyle = window.getComputedStyle(blockToDrag);
                    const x = parseFloat(computedStyle.left);
                    const y = parseFloat(computedStyle.top);

                    // Use peek to get updated blocks and send only the affected block to backend
                    const updatedBlocks = peekUpdateBlockPosition(draggingBlock, { x, y });
                    const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, draggingBlock);
                    if (updatedBlock) {
                        await updateBackend(updatedBlock);
                    }
                }
            }

            // Update backend for element resize
            if (resizingElement && selectedBlock) {
                const elementToResize = document.querySelector(`[data-element-id="${resizingElement}"]`) as HTMLElement;
                if (elementToResize) {
                    const computedStyle = window.getComputedStyle(elementToResize);
                    const width = parseFloat(computedStyle.width);
                    const height = parseFloat(computedStyle.height);

                    // Use peek to get updated blocks and send only the affected block to backend
                    const updatedBlocks = peekUpdateElementSize(selectedBlock, resizingElement, { width, height });
                    const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, selectedBlock);
                    if (updatedBlock) {
                        await updateBackend(updatedBlock);
                    }
                }
            }

            // Update backend for block resize
            if (resizingBlock) {
                const blockToResize = document.querySelector(`[data-block-id="${resizingBlock}"]`) as HTMLElement;
                if (blockToResize) {
                    const computedStyle = window.getComputedStyle(blockToResize);
                    const width = parseFloat(computedStyle.width);
                    const height = parseFloat(computedStyle.height);

                    // Use peek to get updated blocks and send only the affected block to backend
                    const updatedBlocks = peekUpdateBlockSize(resizingBlock, { width, height });
                    const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, resizingBlock);
                    if (updatedBlock) {
                        await updateBackend(updatedBlock);
                    }
                }
            }

            // Reset all dragging states
            setDraggingElement(null);
            setResizingElement(null);
            setDraggingBlock(null);
            setResizingBlock(null);
            setResizeStart(null);
        };

        if (draggingElement || draggingBlock || resizingElement || resizingBlock) {
            document.addEventListener("mousemove", handleMouseMove);
            document.addEventListener("mouseup", handleMouseUp);
        }

        return () => {
            document.removeEventListener("mousemove", handleMouseMove);
            document.removeEventListener("mouseup", handleMouseUp);
        };
    }, [draggingElement, resizingElement, draggingBlock, resizingBlock, elementDragOffset, blockDragOffset, selectedBlock, currentElement, resizeStart, currentBlock, blocks]);

    return (
        <div ref={editorRef} className="dashboard-editor">
            {activeModule === "visualization" && (
                <ControlPanel
                    editMode={editMode}
                    setEditMode={setEditMode}
                    addBlock={async () => {
                        const updatedBlocks = peekAddBlock();
                        const newBlock = updatedBlocks[updatedBlocks.length - 1]; // Get the newly added block
                        if (newBlock) {
                            await updateBackend(newBlock);
                        }
                    }}
                    showDataModelPanel={showDataModelPanel}
                    setShowDataModelPanel={setShowDataModelPanel}
                />
            )}

            {activeModule === "simulation" && isPlaying && <AnalyzerManager />}

            {/* BlockGrid */}

            <div className="block-grid-container">
                <BlockGrid
                    blocks={blocks}
                    handleAddElement={async (blockId, type, graphType) => {
                        const updatedBlocks = peekAddElement(blockId, type, graphType);
                        const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                        if (updatedBlock) {
                            await updateBackend(updatedBlock);
                        }
                    }}
                    editMode={editMode}
                    selectedBlock={selectedBlock}
                    selectedElement={selectedElement}
                    showSwapUI={showSwapUI}
                    swapSource={swapSource}
                    calculateMinBlockSize={calculateMinBlockSize}
                    handleBlockClick={(blockId, event) => handleBlockClick(blockId, event, editMode, setSelectedBlock, setSelectedElement, setShowSwapUI, setShowElementDropdown, showElementDropdown)}
                    handleElementClick={(blockId, elementId, event) =>
                        handleElementClick(blockId, elementId, event, editMode, setSelectedElement, setSelectedBlock, setShowSwapUI, setShowElementDropdown)
                    }
                    handleElementDragStart={(elementId, event) => handleElementDragStart(elementId, event, currentElement, setDraggingElement, setElementDragOffset)}
                    handleElementResizeStart={(elementId, event) => handleElementResizeStart(elementId, event, setResizingElement, setResizeStart)}
                    handleBlockResizeStart={(blockId, event) => handleBlockResizeStart(blockId, event, setResizingBlock, setResizeStart)}
                    handleSwapStart={(elementId, event) => handleSwapStart(elementId, event, setSwapSource, setShowSwapUI)}
                    handleSwapTarget={async (elementId, event) => {
                        if (!selectedBlock) return;
                        handleSwapTarget(elementId, event, swapSource, selectedBlock, async (blockId, el1, el2) => {
                            const updatedBlocks = peekSwapElements(blockId, el1, el2);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        });
                    }}
                    handleBlockDragStart={(blockId, event) => handleBlockDragStart(blockId, event, setDraggingBlock, setBlockDragOffset)}
                    setShowElementDropdown={setShowElementDropdown}
                    showElementDropdown={showElementDropdown}
                    blockRef={blockRef}
                />

                {/* BlockEditor */}

                {selectedBlock && editMode && !selectedElement && currentBlock && (
                    <BlockEditor
                        blockEditorRef={blockEditorRef}
                        currentBlock={currentBlock}
                        selectedBlock={selectedBlock}
                        updateBlockStyle={async (blockId, style) => {
                            const updatedBlocks = peekUpdateBlockStyle(blockId, style);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateBlockSize={async (blockId, size) => {
                            const updatedBlocks = peekUpdateBlockSize(blockId, size);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateBlockPosition={async (blockId, position) => {
                            const updatedBlocks = peekUpdateBlockPosition(blockId, position);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateBlockPositionType={async (blockId, positionType) => {
                            const updatedBlocks = peekUpdateBlockPositionType(blockId, positionType);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateBlockZIndex={async (blockId, zIndex) => {
                            const updatedBlocks = peekUpdateBlockZIndex(blockId, zIndex);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        handleRemoveBlock={async (blockId) => {
                            const block = getBlockById(blockId);
                            if (!block) return;

                            try {
                                const data = await deleteDashBoardBlocksApi({
                                    projectId: projectId!,
                                    versionId: selectedVersion!.versionId,
                                    blocks: [block],
                                });

                                if (data.blocks.length > 0) {
                                    data.blocks.forEach((updatedBlock: any) => {
                                        if (updatedBlock.message === "Block deleted successfully") {
                                            removeBlock(updatedBlock.blockUuid);
                                        }
                                    });
                                }
                            } catch (error) {
                                console.error("Failed to delete block:", error);
                            }
                        }}
                    />
                )}

                {selectedElement && editMode && selectedBlock && currentElement && (
                    <ElementEditor
                        elementEditorRef={elementEditorRef}
                        currentElement={currentElement}
                        selectedBlock={selectedBlock}
                        selectedElement={selectedElement}
                        updateElementStyle={async (blockId, elementId, style) => {
                            const updatedBlocks = peekUpdateElementStyle(blockId, elementId, style);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateElementSize={async (blockId, elementId, size) => {
                            const updatedBlocks = peekUpdateElementSize(blockId, elementId, size);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateElementPosition={async (blockId, elementId, position) => {
                            const updatedBlocks = peekUpdateElementPosition(blockId, elementId, position);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateElementPositionType={async (blockId, elementId, positionType) => {
                            const updatedBlocks = peekUpdateElementPositionType(blockId, elementId, positionType);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateElementZIndex={async (blockId, elementId, zIndex) => {
                            const updatedBlocks = peekUpdateElementZIndex(blockId, elementId, zIndex);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateElementData={async (blockId, elementId, updates) => {
                            const updatedBlocks = peekUpdateElementData(blockId, elementId, updates);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateGraphData={async (blockId, elementId, newData) => {
                            const updatedBlocks = peekUpdateGraphData(blockId, elementId, newData);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateGraphTitle={async (blockId, elementId, title) => {
                            const updatedBlocks = peekUpdateGraphTitle(blockId, elementId, title);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateGraphType={async (blockId, elementId, type) => {
                            const updatedBlocks = peekUpdateGraphType(blockId, elementId, type);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateDataType={async (blockId, elementId, dataType) => {
                            const updatedBlocks = peekUpdateDataType(blockId, elementId, dataType);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateCommonValue={async (blockId, elementId, commonValue) => {
                            const updatedBlocks = peekUpdateCommonValue(blockId, elementId, commonValue);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateDataValue={async (blockId, elementId, dataValue) => {
                            const updatedBlocks = peekUpdateDataValue(blockId, elementId, dataValue);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        updateDataSource={async (blockId, elementId, dataSource) => {
                            const updatedBlocks = peekUpdateDataSource(blockId, elementId, dataSource);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                await updateBackend(updatedBlock);
                            }
                        }}
                        handleRemoveElement={async (blockId, elementId) => {
                            const updatedBlocks = peekRemoveElement(blockId, elementId);
                            const updatedBlock = getBlockFromPeekedBlocks(updatedBlocks, blockId);
                            if (updatedBlock) {
                                // await updateBackend(updatedBlock);
                            }
                        }}
                        setSwapSource={setSwapSource}
                        setShowSwapUI={setShowSwapUI}
                    />
                )}
            </div>

            {showDataModelPanel && editMode && <DataModelPanel dataModel={dataModel} dataModelManager={dataModelManager} />}

            {showSwapUI && <SwapModal setShowSwapUI={setShowSwapUI} setSwapSource={setSwapSource} />}
        </div>
    );
};

export default DashboardEditor;
