"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useDnd = void 0;
var react_1 = require("react");
var ramda_1 = require("ramda");
var types_1 = require("./types");
var useScrollOnDrag_1 = require("./useScrollOnDrag");
var useDelayedDragEventCall_1 = require("./useDelayedDragEventCall");
var helper_1 = require("./helper");
var useDnd = function (_a) {
    var treeData = _a.treeData, containerRef = _a.containerRef, expandNode = _a.expandNode, onLoadChildren = _a.onLoadChildren, onChange = _a.onChange, onDropProp = _a.onDrop, canDrop = _a.canDrop, canDrag = _a.canDrag;
    var _b = (0, react_1.useState)(null), dragNode = _b[0], setDragNode = _b[1];
    var _c = (0, react_1.useState)(null), dropNode = _c[0], setDropNode = _c[1];
    var _d = (0, react_1.useState)(null), dropPositionInfo = _d[0], setDropPositionInfo = _d[1];
    var _e = (0, useScrollOnDrag_1.useScrollOnDrag)(containerRef), onStartDragging = _e.onStartDragging, onEndDragging = _e.onEndDragging, getIsScrolling = _e.getIsScrolling;
    var handleDropOutsideTree = function () {
        setDragNode(null);
        setDropNode(null);
        onEndDragging();
        window.removeEventListener('mousemove', handleDropOutsideTree);
    };
    var onDragStart = function (_a) {
        var node = _a.node;
        setDragNode(node);
        onStartDragging();
        window.addEventListener('mousemove', handleDropOutsideTree);
    };
    var expandedKeys = (0, react_1.useMemo)(function () {
        return (0, helper_1.getExpandedKeys)(treeData);
    }, [treeData]);
    var expandDropNodeAtPosition = (0, react_1.useCallback)(function (pos, expanded) {
        var node = (0, helper_1.getNodeAtPosition)(treeData, pos);
        if (node && !expandedKeys.includes(node.nodeId)) {
            expandNode(pos, expanded);
            if (node.pending && onLoadChildren) {
                onLoadChildren(node);
            }
        }
    }, [expandNode, expandedKeys, onLoadChildren, treeData]);
    var expandDropNode = (0, react_1.useCallback)(function (newDropPositionInfo) {
        if (onChange && newDropPositionInfo.dropPosition === types_1.AddNodePosition.AsChild && dragNode) {
            var currentParentNodePos = (0, helper_1.slideNodePos)(newDropPositionInfo.pos, dragNode.pos);
            if (currentParentNodePos.split('-').length > 1) {
                expandDropNodeAtPosition(currentParentNodePos, true);
            }
        }
    }, [dragNode, expandDropNodeAtPosition, onChange]);
    var handleSetDropNode = (0, react_1.useCallback)(function (_a) {
        var event = _a.event, node = _a.node;
        var newDropPositionInfo = (0, helper_1.getDropNodePosition)(event, node, dropPositionInfo) || dropPositionInfo;
        var isNewDropPositionValid = newDropPositionInfo &&
            dragNode &&
            canDrop({
                // Either drop node itself or its parent in the tree
                nextParent: (0, helper_1.getDropNodeParent)(treeData, newDropPositionInfo, dragNode.pos),
                node: dragNode.value
            });
        if (!(0, ramda_1.equals)(newDropPositionInfo, dropPositionInfo) && (!(0, helper_1.isDropIndicatorNode)(node) || !dropNode)) {
            if (isNewDropPositionValid) {
                setDropPositionInfo(newDropPositionInfo);
            }
            expandDropNode(newDropPositionInfo);
        }
        if (node.key !== (dropNode === null || dropNode === void 0 ? void 0 : dropNode.key) && (!(0, helper_1.isDropIndicatorNode)(node) || isNewDropPositionValid)) {
            setDropNode(node);
        }
    }, [dragNode, dropNode, canDrop, dropPositionInfo, expandDropNode, treeData]);
    var delayedHandleDragOver = (0, useDelayedDragEventCall_1.useDelayedDragEventCall)(handleSetDropNode);
    var onDragOver = function (_a) {
        var event = _a.event, node = _a.node;
        var isScrolling = getIsScrolling();
        if (!isScrolling)
            delayedHandleDragOver({ event: event, node: node });
    };
    var dropIndicatorRender = function () {
        return null;
    };
    var onDragLeave = function (_a) {
        var _b, _c;
        var event = _a.event, node = _a.node;
        var draggedChildrenNodes = ((_b = dragNode === null || dragNode === void 0 ? void 0 : dragNode.value) === null || _b === void 0 ? void 0 : _b.expanded) ? (0, helper_1.getExpandedKeys)((_c = dragNode.value) === null || _c === void 0 ? void 0 : _c.children) : [];
        if (draggedChildrenNodes.includes(node.key)) {
            handleSetDropNode({ event: event, node: node });
        }
    };
    var onDrop = function () {
        if (dragNode && dropPositionInfo && (0, helper_1.isDropIndicatorNode)(dropNode)) {
            var parentNode = (0, helper_1.getDropNodeParent)(treeData, dropPositionInfo, dragNode.pos);
            if (canDrop({ nextParent: parentNode, node: dragNode.value })) {
                var newTreeData = (0, helper_1.moveNode)(treeData, dragNode.value, dragNode.pos, dropPositionInfo);
                onDropProp(newTreeData, dragNode.value, parentNode);
            }
        }
        setDragNode(null);
        setDropNode(null);
        onEndDragging();
        window.removeEventListener('mousemove', handleDropOutsideTree);
    };
    var nodeDraggable = (0, react_1.useCallback)(function (node) {
        return canDrag({ node: node.value });
    }, [canDrag]);
    return {
        treeProps: {
            onDragStart: onDragStart,
            onDragOver: onDragOver,
            onDragLeave: onDragLeave,
            onDrop: onDrop,
            dropIndicatorRender: dropIndicatorRender
        },
        nodeDraggable: nodeDraggable,
        dropNode: dropNode,
        dragNode: dragNode,
        dropPositionInfo: dropPositionInfo
    };
};
exports.useDnd = useDnd;
