import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/* eslint-disable no-negated-condition */
import * as React from 'react';
import { isKeyboardEvent } from '@dnd-kit/dom/utilities';
import { move } from '@dnd-kit/helpers';
import { DragDropProvider, DragOverlay } from '@dnd-kit/react';
import { TrashBin } from '@gravity-ui/icons';
import { Button, Icon } from '@gravity-ui/uikit';
import { useMainEditorStore } from "../../hooks/index.js";
import { generateChildrenPathFromArray, getItemTitle } from "../../utils/index.js";
import { editorCn } from "../../utils/cn.js";
import { TreeItem } from "./TreeItem.js";
import { TreeItemOverlay } from "./TreeItemOverlay.js";
import { blocksToTreeItems, getBlockTypeLabel, idToBlockPath, treeItemsToBlocks, } from "./utils/blocksBridge.js";
import { buildTree, flattenTree, getDescendants, getDragDepth } from "./utils/common.js";
import { sanitizeProjectionForChildrenCapability } from "./utils/treeDragGuards.js";
import './Tree.css';
const b = editorCn('tree');
const INDENTATION = 24;
const Tree = ({ className }) => {
    const { content, setContent, selectedBlock, setSelectedBlock, resetBlocks, duplicateBlock, deleteBlock, } = useMainEditorStore();
    const [flattenedItems, setFlattenedItems] = React.useState(() => flattenTree(blocksToTreeItems(content.blocks)));
    const initialDepth = React.useRef(0);
    const sourceChildren = React.useRef([]);
    React.useEffect(() => {
        setFlattenedItems(flattenTree(blocksToTreeItems(content.blocks)));
    }, [content.blocks]);
    const selectedBlockPathStr = React.useMemo(() => generateChildrenPathFromArray(selectedBlock || []), [selectedBlock]);
    const handleDragStart = React.useCallback((event) => {
        const { source } = event.operation;
        if (!source) {
            return;
        }
        const row = flattenedItems.find(({ id }) => id === source.id);
        if (!row) {
            return;
        }
        initialDepth.current = row.depth;
        setFlattenedItems((flatItems) => {
            sourceChildren.current = [];
            const descendants = getDescendants(flatItems, source.id);
            return flatItems.filter((item) => {
                if (descendants.has(item.id)) {
                    sourceChildren.current = [...sourceChildren.current, item];
                    return false;
                }
                return true;
            });
        });
    }, [flattenedItems]);
    const handleDragOver = React.useCallback((event, manager) => {
        event.preventDefault();
        const { source, target } = event.operation;
        if (source && target && source.id !== target.id) {
            setFlattenedItems((flat) => {
                const offsetLeft = manager.dragOperation.transform.x;
                const dragDepth = getDragDepth(offsetLeft, INDENTATION);
                const projectedDepth = initialDepth.current + dragDepth;
                const { depth, parentId } = sanitizeProjectionForChildrenCapability(flat, target.id, projectedDepth);
                const sortedItems = move(flat, event);
                return sortedItems.map((item) => item.id === source.id ? { ...item, depth, parentId } : item);
            });
        }
    }, []);
    const handleDragMove = React.useCallback((event, manager) => {
        if (event.defaultPrevented) {
            return;
        }
        const { source, target } = event.operation;
        if (source && target) {
            const keyboard = isKeyboardEvent(event.operation.activatorEvent);
            const currentDepth = source.data?.depth ?? 0;
            let keyboardDepth;
            if (keyboard) {
                const isHorizontal = event.by?.x !== 0 && event.by?.y === 0;
                if (isHorizontal) {
                    event.preventDefault();
                    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
                    keyboardDepth = currentDepth + Math.sign(event.by.x);
                }
            }
            const offsetLeft = manager.dragOperation.transform.x;
            const dragDepth = getDragDepth(offsetLeft, INDENTATION);
            const projectedDepth = keyboardDepth ?? initialDepth.current + dragDepth;
            const { depth, parentId } = sanitizeProjectionForChildrenCapability(flattenedItems, source.id, projectedDepth);
            if (keyboard) {
                if (currentDepth !== depth) {
                    const offset = INDENTATION * (depth - currentDepth);
                    manager.actions.move({
                        by: { x: offset, y: 0 },
                        propagate: false,
                    });
                }
            }
            if (source.data?.depth !== depth || source.data?.parentId !== parentId) {
                setFlattenedItems((flat) => flat.map((item) => item.id === source.id ? { ...item, depth, parentId } : item));
            }
        }
    }, [flattenedItems]);
    const handleDragEnd = React.useCallback((event) => {
        if (event.canceled) {
            setFlattenedItems(flattenTree(blocksToTreeItems(content.blocks)));
            return;
        }
        const merged = [...flattenedItems, ...sourceChildren.current];
        const updatedTree = buildTree(merged);
        const nextFlat = flattenTree(updatedTree);
        const newBlocks = treeItemsToBlocks(updatedTree);
        setFlattenedItems(nextFlat);
        setContent({ ...content, blocks: newBlocks });
        const draggedId = event.operation.source?.id;
        const pathToDragged = draggedId !== null ? idToBlockPath(nextFlat, String(draggedId)) : [];
        setSelectedBlock(pathToDragged.length ? pathToDragged : null);
    }, [setContent, setSelectedBlock, content, flattenedItems]);
    return (_jsxs("div", { className: b(null, className), children: [_jsx("div", { className: b('head'), children: _jsxs(Button, { view: "outlined-danger", onClick: () => resetBlocks(), children: [_jsx(Icon, { data: TrashBin }), "Clear all"] }) }), _jsxs(DragDropProvider, { onDragStart: handleDragStart, onDragOver: handleDragOver, onDragMove: handleDragMove, onDragEnd: handleDragEnd, children: [_jsx("div", { className: b('list'), children: flattenedItems.map((row, index) => {
                            const path = idToBlockPath(flattenedItems, row.id);
                            const pathKey = generateChildrenPathFromArray(path);
                            const blockType = getBlockTypeLabel(row.block);
                            return (_jsx(TreeItem, { item: row, sortableIndex: index, indentLeft: row.depth * INDENTATION, path: path, selected: selectedBlockPathStr === pathKey, type: blockType, treeTitle: getItemTitle(row.block), onCopy: duplicateBlock, onDelete: deleteBlock, onSelect: setSelectedBlock }, row.id));
                        }) }), _jsx(DragOverlay, { className: b('dnd-overlay'), dropAnimation: null, children: (source) => {
                            if (!source) {
                                return null;
                            }
                            const sourceId = String(source.id);
                            const rowNow = flattenedItems.find(({ id }) => String(id) === sourceId);
                            const overlayBlock = rowNow?.block;
                            if (!overlayBlock) {
                                return null;
                            }
                            const indentLeft = (rowNow?.depth ?? 0) * INDENTATION;
                            return (_jsx(TreeItemOverlay, { block: overlayBlock, count: sourceChildren.current.length, indentLeft: indentLeft }));
                        } })] })] }));
};
export default Tree;
//# sourceMappingURL=Tree.js.map
