var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
import classnames from 'classnames';
import { assoc, identity } from 'ramda';
import Tree from 'rc-tree';
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import DragIndicator from '@mui/icons-material/DragIndicator';
import ReactResizeDetector from 'react-resize-detector';
import { noop } from '@reltio/mdm-sdk';
import { RCTreeSwitchRenderer } from './RCTreeSwitchRenderer';
import { RCTreeLevelLines } from './RCTreeLevelLines';
import { changeNodeAtPosition, convertTreeData, defaultIsLeaf, gatherNodeKeys, getExpandedKeys, isDropIndicatorNode, moveNode, getLevelLinesData, calcNodeWidth, getTreeMaxWidth } from './helper';
import { useDnd } from './useDnd';
import { useStyles } from './styles';
var MIN_ROW_HEIGHT = 28;
var returnFalse = function () { return false; };
export var RCTree = function (_a) {
    var _b;
    var treeData = _a.treeData, _c = _a.isVirtualized, isVirtualized = _c === void 0 ? true : _c, _d = _a.canDrag, canDragProp = _d === void 0 ? returnFalse : _d, _e = _a.canDrop, canDrop = _e === void 0 ? returnFalse : _e, _f = _a.onDrop, onDrop = _f === void 0 ? noop : _f, onLoadChildren = _a.onLoadChildren, _g = _a.defaultExpandAll, defaultExpandAll = _g === void 0 ? false : _g, _h = _a.SwitchRenderer, SwitchRenderer = _h === void 0 ? RCTreeSwitchRenderer : _h, _j = _a.LevelLinesRenderer, LevelLinesRenderer = _j === void 0 ? RCTreeLevelLines : _j, className = _a.className, renderNode = _a.renderNode, _k = _a.minItemHeight, minItemHeight = _k === void 0 ? MIN_ROW_HEIGHT : _k, _l = _a.isLeaf, isLeaf = _l === void 0 ? defaultIsLeaf : _l, scrollToNode = _a.scrollToNode, _m = _a.onChange, onChange = _m === void 0 ? identity : _m, height = _a.height;
    var styles = useStyles();
    var treeRef = useRef(null);
    var containerRef = useRef(null);
    var _o = useState({ width: 0, height: 0 }), containerSize = _o[0], setContainerSize = _o[1];
    var _p = useState(true), isDraggingEnabled = _p[0], setIsDraggingEnabled = _p[1];
    var expandNode = useCallback(function (pos, expanded) {
        var changeNode = assoc('expanded', expanded);
        var newTreeData = changeNodeAtPosition(treeData, pos, changeNode);
        if (newTreeData)
            onChange(newTreeData);
    }, [onChange, treeData]);
    var canDrag = useCallback(function (params) { return isDraggingEnabled && canDragProp(params); }, [canDragProp, isDraggingEnabled]);
    var _q = useDnd({
        containerRef: containerRef,
        treeData: treeData,
        expandNode: expandNode,
        onLoadChildren: onLoadChildren,
        onChange: onChange,
        onDrop: onDrop,
        canDrop: canDrop,
        canDrag: canDrag
    }), treeProps = _q.treeProps, nodeDraggable = _q.nodeDraggable, dropNode = _q.dropNode, dragNode = _q.dragNode, dropPositionInfo = _q.dropPositionInfo;
    useEffect(function () {
        if (treeRef.current && scrollToNode) {
            treeRef.current.scrollTo({ key: String(scrollToNode.nodeId) });
        }
    }, [scrollToNode]);
    var diplayedTreeData = useMemo(function () {
        if (dropNode && dragNode && dropPositionInfo) {
            if (dropNode.pos === dragNode.pos && dropNode.key === dragNode.key)
                return treeData;
            var dragNodeValue = __assign(__assign({}, dragNode.value), { nodeId: -1 });
            return moveNode(treeData, dragNodeValue, dragNode.pos, dropPositionInfo);
        }
        return treeData;
    }, [treeData, dragNode, dropNode, dropPositionInfo]);
    var expandedKeys = useMemo(function () {
        return getExpandedKeys(diplayedTreeData);
    }, [diplayedTreeData]);
    var levelLines = useMemo(function () { return getLevelLinesData(diplayedTreeData); }, [diplayedTreeData]);
    var internalTreeData = useMemo(function () { return convertTreeData({ data: diplayedTreeData, isLeaf: isLeaf }); }, [isLeaf, diplayedTreeData]);
    var handleExpand = useCallback(function (_expandedKeys, data) {
        if (onChange && !dragNode) {
            expandNode(data.node.pos, data.expanded);
        }
    }, [onChange, expandNode, dragNode]);
    var renderSwitcherIcon = useCallback(function (node) { return React.createElement(SwitchRenderer, { node: node }); }, [SwitchRenderer]);
    var handleEnableDragging = useCallback(function () {
        setIsDraggingEnabled(true);
        window.removeEventListener('mouseup', handleEnableDragging);
        window.removeEventListener('dragend', handleEnableDragging);
    }, []);
    var handleDisableDragging = useCallback(function () {
        setIsDraggingEnabled(false);
        window.addEventListener('mouseup', handleEnableDragging);
        window.addEventListener('dragend', handleEnableDragging);
    }, [handleEnableDragging]);
    useEffect(function () {
        return function () {
            window.removeEventListener('mouseup', handleEnableDragging);
            window.removeEventListener('dragend', handleEnableDragging);
        };
    }, [handleEnableDragging]);
    var titleRender = function (node) {
        var _a;
        var _b, _c;
        var draggedNodes = gatherNodeKeys(dragNode);
        var width = calcNodeWidth((_c = (_b = levelLines[node.key]) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.length, containerSize.width);
        return (React.createElement("div", { "data-reltio-id": "rc-tree-title-wrapper", className: classnames(styles.titleWrapper, (_a = {},
                _a[styles.dropIndicator] = isDropIndicatorNode(node),
                _a[styles.dropNotAllowed] = dropNode && !isDropIndicatorNode(dropNode),
                _a[styles.draggedChildrenNode] = draggedNodes.includes(node.key),
                _a)), onMouseDown: handleDisableDragging, style: { width: width } },
            React.createElement(LevelLinesRenderer, { levelLine: levelLines[node.key] }),
            renderNode ? renderNode(node.value) : node.title));
    };
    var dragHandle = (React.createElement("span", { className: classnames(styles.dragHandle, (_b = {}, _b[styles.dragHandleDragging] = !!dragNode, _b)) },
        React.createElement(DragIndicator, null)));
    var onContainerResize = useCallback(function (width, height) {
        setContainerSize({ width: width, height: height });
    }, []);
    var scrollWidth = useMemo(function () {
        return isVirtualized ? Math.max(getTreeMaxWidth(diplayedTreeData), containerSize.width) : null;
    }, [diplayedTreeData, isVirtualized, containerSize.width]);
    return diplayedTreeData ? (React.createElement("div", { ref: containerRef, className: classnames(styles.treeContainer) },
        React.createElement(ReactResizeDetector, { handleWidth: true, handleHeight: true, onResize: onContainerResize }),
        React.createElement(Tree, __assign({ draggable: {
                icon: dragHandle,
                nodeDraggable: nodeDraggable
            }, virtual: isVirtualized, itemHeight: minItemHeight, height: height || containerSize.height, onExpand: handleExpand, showIcon: false, switcherIcon: renderSwitcherIcon, defaultExpandAll: defaultExpandAll, expandedKeys: expandedKeys, className: classnames(className, styles.treeWrapper), titleRender: titleRender, treeData: internalTreeData, selectable: false, loadData: onLoadChildren ? function (node) { return onLoadChildren(node.value); } : undefined, scrollWidth: scrollWidth, "data-reltio-id": "rc-tree", ref: treeRef }, treeProps)))) : null;
};
