"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const jsx_runtime_1 = require("react/jsx-runtime");
/* eslint-disable no-negated-condition */
const React = tslib_1.__importStar(require("react"));
const utilities_1 = require("@dnd-kit/dom/utilities");
const helpers_1 = require("@dnd-kit/helpers");
const react_1 = require("@dnd-kit/react");
const icons_1 = require("@gravity-ui/icons");
const uikit_1 = require("@gravity-ui/uikit");
const hooks_1 = require("../../hooks/index.js");
const utils_1 = require("../../utils/index.js");
const cn_1 = require("../../utils/cn.js");
const TreeItem_1 = require("./TreeItem.js");
const TreeItemOverlay_1 = require("./TreeItemOverlay.js");
const blocksBridge_1 = require("./utils/blocksBridge.js");
const common_1 = require("./utils/common.js");
const treeDragGuards_1 = require("./utils/treeDragGuards.js");
const b = (0, cn_1.editorCn)('tree');
const INDENTATION = 24;
const Tree = ({ className }) => {
    const { content, setContent, selectedBlock, setSelectedBlock, resetBlocks, duplicateBlock, deleteBlock, } = (0, hooks_1.useMainEditorStore)();
    const [flattenedItems, setFlattenedItems] = React.useState(() => (0, common_1.flattenTree)((0, blocksBridge_1.blocksToTreeItems)(content.blocks)));
    const initialDepth = React.useRef(0);
    const sourceChildren = React.useRef([]);
    React.useEffect(() => {
        setFlattenedItems((0, common_1.flattenTree)((0, blocksBridge_1.blocksToTreeItems)(content.blocks)));
    }, [content.blocks]);
    const selectedBlockPathStr = React.useMemo(() => (0, utils_1.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 = (0, common_1.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 = (0, common_1.getDragDepth)(offsetLeft, INDENTATION);
                const projectedDepth = initialDepth.current + dragDepth;
                const { depth, parentId } = (0, treeDragGuards_1.sanitizeProjectionForChildrenCapability)(flat, target.id, projectedDepth);
                const sortedItems = (0, helpers_1.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 = (0, utilities_1.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 = (0, common_1.getDragDepth)(offsetLeft, INDENTATION);
            const projectedDepth = keyboardDepth ?? initialDepth.current + dragDepth;
            const { depth, parentId } = (0, treeDragGuards_1.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((0, common_1.flattenTree)((0, blocksBridge_1.blocksToTreeItems)(content.blocks)));
            return;
        }
        const merged = [...flattenedItems, ...sourceChildren.current];
        const updatedTree = (0, common_1.buildTree)(merged);
        const nextFlat = (0, common_1.flattenTree)(updatedTree);
        const newBlocks = (0, blocksBridge_1.treeItemsToBlocks)(updatedTree);
        setFlattenedItems(nextFlat);
        setContent({ ...content, blocks: newBlocks });
        const draggedId = event.operation.source?.id;
        const pathToDragged = draggedId !== null ? (0, blocksBridge_1.idToBlockPath)(nextFlat, String(draggedId)) : [];
        setSelectedBlock(pathToDragged.length ? pathToDragged : null);
    }, [setContent, setSelectedBlock, content, flattenedItems]);
    return ((0, jsx_runtime_1.jsxs)("div", { className: b(null, className), children: [(0, jsx_runtime_1.jsx)("div", { className: b('head'), children: (0, jsx_runtime_1.jsxs)(uikit_1.Button, { view: "outlined-danger", onClick: () => resetBlocks(), children: [(0, jsx_runtime_1.jsx)(uikit_1.Icon, { data: icons_1.TrashBin }), "Clear all"] }) }), (0, jsx_runtime_1.jsxs)(react_1.DragDropProvider, { onDragStart: handleDragStart, onDragOver: handleDragOver, onDragMove: handleDragMove, onDragEnd: handleDragEnd, children: [(0, jsx_runtime_1.jsx)("div", { className: b('list'), children: flattenedItems.map((row, index) => {
                            const path = (0, blocksBridge_1.idToBlockPath)(flattenedItems, row.id);
                            const pathKey = (0, utils_1.generateChildrenPathFromArray)(path);
                            const blockType = (0, blocksBridge_1.getBlockTypeLabel)(row.block);
                            return ((0, jsx_runtime_1.jsx)(TreeItem_1.TreeItem, { item: row, sortableIndex: index, indentLeft: row.depth * INDENTATION, path: path, selected: selectedBlockPathStr === pathKey, type: blockType, treeTitle: (0, utils_1.getItemTitle)(row.block), onCopy: duplicateBlock, onDelete: deleteBlock, onSelect: setSelectedBlock }, row.id));
                        }) }), (0, jsx_runtime_1.jsx)(react_1.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 ((0, jsx_runtime_1.jsx)(TreeItemOverlay_1.TreeItemOverlay, { block: overlayBlock, count: sourceChildren.current.length, indentLeft: indentLeft }));
                        } })] })] }));
};
exports.default = Tree;
//# sourceMappingURL=Tree.js.map
