import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from 'react';
import { ChevronDown, ChevronUp, Copy, TrashBin } from '@gravity-ui/icons';
import { Button, Icon } from '@gravity-ui/uikit';
import _ from 'lodash';
import { usePostMessageAPIListener } from "../../../common/postMessage.js";
import { getCursorPositionOverElement } from "../../../utils/editor.js";
import { useMainEditorStore } from "../../hooks/useMainEditorStore.js";
import { editorCn } from "../../utils/cn.js";
import './Overlay.css';
const b = editorCn('overlay');
const findRectByPath = (rectMap, path) => {
    if (!path)
        return null;
    return rectMap.find((entry) => _.isEqual(entry.path, path))?.rect ?? null;
};
const Overlay = ({ className, canvasElement }) => {
    const { rectMap, setRectMap, selectedBlock, setSelectedBlock, deleteBlock, duplicateBlock, manipulateOverlayMode, preInsertBlockType, preReorderBlockPath, insertBlock, reorderBlock, disableMode, } = useMainEditorStore();
    const [hoveredPath, setHoveredPath] = React.useState(null);
    const [insertPosition, setInsertPosition] = React.useState(null);
    usePostMessageAPIListener('ON_UPDATE_RECT_MAP', ({ rects }) => {
        setRectMap(rects);
    }, [setRectMap]);
    const selectedRect = React.useMemo(() => findRectByPath(rectMap, selectedBlock), [rectMap, selectedBlock]);
    const hoveredRect = React.useMemo(() => findRectByPath(rectMap, hoveredPath), [rectMap, hoveredPath]);
    // Auto-scroll to selected block when it changes
    React.useEffect(() => {
        if (selectedRect && canvasElement) {
            const canvasHeight = canvasElement.clientHeight;
            const scrollPosition = selectedRect.top - canvasHeight / 2 + selectedRect.height / 2;
            canvasElement.scrollTo({
                top: Math.max(0, scrollPosition),
                behavior: 'smooth',
            });
        }
        // Intentionally depends on selectedBlock identity (path), not rect value, to avoid scroll jitter on rect updates.
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [selectedBlock, canvasElement]);
    const handleClick = React.useCallback((path) => {
        if (selectedBlock && _.isEqual(selectedBlock, path)) {
            setSelectedBlock(null);
        }
        else {
            setSelectedBlock(path);
        }
    }, [selectedBlock, setSelectedBlock]);
    const handleMouseEnter = React.useCallback((path) => {
        setHoveredPath(path);
    }, []);
    const handleMouseLeave = React.useCallback((path) => {
        setHoveredPath((current) => (_.isEqual(current, path) ? null : current));
    }, []);
    const handleMouseMove = React.useCallback((e) => {
        if (!manipulateOverlayMode) {
            return;
        }
        const domRect = e.currentTarget.getBoundingClientRect();
        const position = getCursorPositionOverElement(domRect, e);
        setInsertPosition(position);
    }, [manipulateOverlayMode]);
    const handleKeyDown = React.useCallback((e, path) => {
        if (e.key === 'Enter' || e.key === ' ') {
            e.stopPropagation();
            handleClick(path);
        }
    }, [handleClick]);
    const handleMouseUp = React.useCallback((path) => {
        if (!manipulateOverlayMode)
            return;
        const position = insertPosition;
        const prepend = position === 'left' || position === 'top';
        if (manipulateOverlayMode === 'insert' && preInsertBlockType) {
            insertBlock(path, preInsertBlockType, prepend ? 'prepend' : 'append');
        }
        else if (manipulateOverlayMode === 'reorder' && preReorderBlockPath) {
            reorderBlock(preReorderBlockPath, path, prepend ? 'prepend' : 'append');
        }
        disableMode();
        setInsertPosition(null);
    }, [
        manipulateOverlayMode,
        preInsertBlockType,
        preReorderBlockPath,
        insertBlock,
        reorderBlock,
        disableMode,
        insertPosition,
    ]);
    const handleMoveUp = () => {
        if (!selectedBlock)
            return;
        const destination = [...selectedBlock];
        const newLastDestination = destination[destination.length - 1] - 1;
        if (newLastDestination < 0) {
            return;
        }
        destination[destination.length - 1] = newLastDestination;
        reorderBlock(selectedBlock, destination, 'prepend');
    };
    const handleMoveDown = () => {
        if (!selectedBlock)
            return;
        const destination = [...selectedBlock];
        const newLastDestination = destination[destination.length - 1] + 1;
        destination[destination.length - 1] = newLastDestination;
        reorderBlock(selectedBlock, destination, 'append');
    };
    const showHoverBorder = hoveredRect && (!selectedBlock || !_.isEqual(hoveredPath, selectedBlock));
    return (_jsxs("div", { className: b(null, className), children: [rectMap.map(({ path, rect, dropZone }) => {
                const key = path.join('.');
                return (_jsx("div", { role: dropZone ? 'presentation' : 'button', tabIndex: dropZone ? -1 : 0, className: b('hit'), style: {
                        top: rect.top,
                        left: rect.left,
                        width: rect.width,
                        height: rect.height,
                        zIndex: 10 * (path.length + (dropZone ? 0 : 1)),
                    }, onClick: dropZone
                        ? undefined
                        : (e) => {
                            e.stopPropagation();
                            handleClick(path);
                        }, onKeyDown: dropZone ? undefined : (e) => handleKeyDown(e, path), onMouseEnter: () => handleMouseEnter(path), onMouseLeave: () => handleMouseLeave(path), onMouseMove: (e) => handleMouseMove(e), onMouseUp: () => handleMouseUp(path) }, key));
            }), selectedRect ? (_jsx("div", { className: b('border'), style: {
                    top: selectedRect.top,
                    left: selectedRect.left,
                    width: selectedRect.width,
                    height: selectedRect.height,
                }, children: _jsxs("div", { className: b('actions'), children: [_jsx("div", { className: b('actions-box', { reorder: true }), children: _jsx(Button, { view: "flat", size: 'm', onClick: handleMoveUp, children: _jsx(Icon, { className: b('reorder-icon'), data: ChevronUp, size: 18 }) }) }), _jsxs("div", { className: b('actions-box', { main: true }), children: [_jsx(Button, { className: b('action-button'), size: 'm', view: 'action', onClick: () => selectedBlock && duplicateBlock(selectedBlock), children: _jsx(Icon, { data: Copy, size: 18 }) }), _jsx(Button, { className: b('action-button'), size: 'm', view: 'action', onClick: () => selectedBlock && deleteBlock(selectedBlock), children: _jsx(Icon, { data: TrashBin, size: 18 }) })] }), _jsx("div", { className: b('actions-box', { reorder: true }), children: _jsx(Button, { view: "flat", size: 'm', onClick: handleMoveDown, children: _jsx(Icon, { className: b('reorder-icon'), data: ChevronDown, size: 18 }) }) })] }) })) : null, showHoverBorder ? (_jsx("div", { className: b('border', { hover: true }), style: {
                    top: hoveredRect.top,
                    left: hoveredRect.left,
                    width: hoveredRect.width,
                    height: hoveredRect.height,
                } })) : null, manipulateOverlayMode && hoveredRect && insertPosition ? (_jsx("div", { className: b('line', { position: insertPosition }), style: {
                    top: hoveredRect.top,
                    left: hoveredRect.left,
                    width: hoveredRect.width,
                    height: hoveredRect.height,
                } })) : null] }));
};
export default Overlay;
//# sourceMappingURL=Overlay.js.map
