import React, { useCallback, useState, useEffect, useRef } from 'react';
import { makeStyles, useTheme, lighten, CircularProgress, Typography } from '@material-ui/core';
import TreeView from '@material-ui/lab/TreeView';
import { BaseTreeMenuItem } from './BaseTreeMenuItem';
import { searchTree, findAllParentIds, getNodeIdForRightBorder } from '../utilities/tree/TreeUtilities';
import { FluentIcon } from '../utilities/iconLibrary/FluentIcon';
import { CaretUpSolid8Icon, CaretDownSolid8Icon } from '@fluentui/react-icons';
import { cloneDeep } from 'lodash-es';
import { TreeViewModeEnums } from '../enums/unitySystemEnums.ts';
const useStyles = makeStyles((theme) => ({
    root: {
        marginBottom: theme.spacing(1.75),
        borderTop: (props) => props.treeViewMode === TreeViewModeEnums.Compact
            ? `1px solid ${theme.palette.grey[200]}`
            : ''
    },
    noChildrenContainer: {
        borderBottom: (props) => props.treeViewMode === TreeViewModeEnums.Compact
            ? `1px solid ${theme.palette.grey[200]}`
            : ''
    }
}));
export const BaseTreeMenu = (props) => {
    const { menuItems, onSelectNode, onDropNode, menuIndex, selectedNodeId, selectedNodeParentId, sidebarExpanded, treeViewMode, childrenKey = 'children' } = props;
    const [expanded, setExpanded] = useState(null);
    const [isCurrentActiveTree, setIsCurrentActiveTree] = useState(false);
    const [selectedNodeIsHidden, setSelectedNodeIsHidden] = useState(false);
    const [tree, setTree] = useState(menuItems);
    const theme = useTheme();
    const classes = useStyles(props);
    const firstRender = useRef(true);
    const handleSelectedNode = useCallback((e, value) => {
        const selectedNode = searchTree(tree, value);
        if (onSelectNode) {
            onSelectNode(selectedNode, menuIndex);
            setSelectedNodeIsHidden(false);
        }
    }, [tree, menuIndex, onSelectNode]);
    const renderTree = useCallback((node, depth = 1) => {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8;
        let label = ((_a = node.properties) === null || _a === void 0 ? void 0 : _a.nodeLabel) || ((_b = node.properties) === null || _b === void 0 ? void 0 : _b.name);
        let subLabel = (_c = node.properties) === null || _c === void 0 ? void 0 : _c.nodeSubLabel;
        let iconName = (_e = (_d = node.properties) === null || _d === void 0 ? void 0 : _d.defaultIcon) === null || _e === void 0 ? void 0 : _e.name;
        let iconType = (_g = (_f = node.properties) === null || _f === void 0 ? void 0 : _f.defaultIcon) === null || _g === void 0 ? void 0 : _g.type;
        let conditionalIconName = ((_h = node.properties) === null || _h === void 0 ? void 0 : _h.conditionalIconName) || '';
        let conditionalIconType = ((_j = node.properties) === null || _j === void 0 ? void 0 : _j.conditionalIconName)
            ? node.properties.conditionalIconType
            : '';
        let conditionalIconColor = ((_k = node.properties) === null || _k === void 0 ? void 0 : _k.conditionalIconName)
            ? (_l = node.properties) === null || _l === void 0 ? void 0 : _l.conditionalIconColor
            : '';
        let nodeId = node.id;
        let iconColor = ((_m = node.properties) === null || _m === void 0 ? void 0 : _m.conditionalIconName)
            ? (_o = node.properties) === null || _o === void 0 ? void 0 : _o.conditionalIconColor
            : (_r = (_q = (_p = node.properties) === null || _p === void 0 ? void 0 : _p.defaultIcon) === null || _q === void 0 ? void 0 : _q.color) === null || _r === void 0 ? void 0 : _r.hex;
        let aggregateThresholdId = ((_s = node.properties) === null || _s === void 0 ? void 0 : _s.aggregateThresholdId) || '';
        if (node.isGroupNode) {
            label = (_t = node.properties) === null || _t === void 0 ? void 0 : _t.label;
            subLabel = (_u = node.properties) === null || _u === void 0 ? void 0 : _u.subLabel;
            iconName = (_w = (_v = node.properties) === null || _v === void 0 ? void 0 : _v.icon) === null || _w === void 0 ? void 0 : _w.name;
            iconType = (_y = (_x = node.properties) === null || _x === void 0 ? void 0 : _x.icon) === null || _y === void 0 ? void 0 : _y.type;
            iconColor = (_1 = (_0 = (_z = node.properties) === null || _z === void 0 ? void 0 : _z.icon) === null || _0 === void 0 ? void 0 : _0.color) === null || _1 === void 0 ? void 0 : _1.hex;
        }
        return (React.createElement(BaseTreeMenuItem, { key: nodeId, nodeId: nodeId, label: label, subLabel: subLabel, iconName: iconName, iconType: iconType, conditionalIconName: conditionalIconName, conditionalIconType: conditionalIconType, conditionalIconColor: conditionalIconColor, parentId: node.parentId, iconColor: iconColor, onNodeSelect: handleSelectedNode, selectedNodeId: selectedNodeId, isSelectedNode: selectedNodeId === node.id, showRightBorderColor: selectedNodeIsHidden &&
                isCurrentActiveTree &&
                getNodeIdForRightBorder(expanded, tree, selectedNodeParentId) ===
                    node.id, isCurrentActiveTree: isCurrentActiveTree, sidebarExpanded: sidebarExpanded, depth: depth, hideExpansion: !!!((_2 = node[childrenKey]) === null || _2 === void 0 ? void 0 : _2.length), node: node, onDropNode: onDropNode, treeViewMode: treeViewMode, menuIndex: menuIndex, aggregateThresholdId: aggregateThresholdId }, ((_3 = node.properties) === null || _3 === void 0 ? void 0 : _3.lazyLoad) &&
            !!!((_4 = node[childrenKey]) === null || _4 === void 0 ? void 0 : _4.length) &&
            !node.completedLoadingChildren && (React.createElement(CircularProgress, { size: 12, style: { marginLeft: (depth || 1) * theme.spacing(1) } })), ((_5 = node.properties) === null || _5 === void 0 ? void 0 : _5.lazyLoad) &&
            !!!((_6 = node[childrenKey]) === null || _6 === void 0 ? void 0 : _6.length) &&
            node.completedLoadingChildren &&
            sidebarExpanded &&
            !node.errorRetrievingChildren && (React.createElement("div", { className: classes.noChildrenContainer }, React.createElement(Typography, { variant: "caption", style: {
                marginLeft: (depth || 1) * theme.spacing(3),
                fontWeight: 400
            } }, "No Childre"))), ((_7 = node.properties) === null || _7 === void 0 ? void 0 : _7.lazyLoad) &&
            node.completedLoadingChildren &&
            sidebarExpanded &&
            node.errorRetrievingChildren && (React.createElement("div", { className: classes.noChildrenContainer }, React.createElement(Typography, { variant: "caption", style: {
                marginLeft: (depth || 1) * theme.spacing(3),
                fontWeight: 400
            } }, `Error Retrieving ${!!((_8 = node[childrenKey]) === null || _8 === void 0 ? void 0 : _8.length) ? `Additional ` : ''}Children`))), Array.isArray(node[childrenKey])
            ? node[childrenKey].map((n, i) => renderTree(n, depth + 1))
            : null));
    }, [
        handleSelectedNode,
        selectedNodeId,
        selectedNodeIsHidden,
        isCurrentActiveTree,
        sidebarExpanded,
        expanded,
        tree,
        selectedNodeParentId,
        theme,
        classes,
        onDropNode,
        treeViewMode,
        menuIndex,
        childrenKey
    ]);
    const handleNodeExpansion = useCallback(async (evt, nodeIds) => {
        const treeCopy = cloneDeep(tree);
        setExpanded(nodeIds);
        const parentNode = searchTree(treeCopy, selectedNodeParentId);
        const initialAllParentNodeIds = selectedNodeParentId
            ? [selectedNodeParentId]
            : [];
        const allParentNodeIds = findAllParentIds(treeCopy, parentNode, initialAllParentNodeIds);
        const selectedNodeShown = allParentNodeIds.every((id) => nodeIds.includes(id));
        if (isCurrentActiveTree &&
            allParentNodeIds.length &&
            !selectedNodeShown) {
            setSelectedNodeIsHidden(true);
        }
        else {
            setSelectedNodeIsHidden(false);
        }
    }, [isCurrentActiveTree, tree, selectedNodeParentId]);
    const getExpandedRecursively = useCallback((tree) => {
        if (!tree)
            return [];
        return tree.reduce((expandedIds, item) => {
            var _a;
            if (item === null || item === void 0 ? void 0 : item.isExpanded) {
                expandedIds.push(item.id);
            }
            if (item && ((_a = item[childrenKey]) === null || _a === void 0 ? void 0 : _a.length)) {
                expandedIds = expandedIds.concat(getExpandedRecursively(item[childrenKey]));
            }
            return expandedIds;
        }, []);
    }, [childrenKey]);
    useEffect(() => {
        setTree(menuItems);
    }, [menuItems]);
    useEffect(() => {
        if (!tree)
            return;
        if (firstRender.current) {
            let expanded = [];
            if (tree === null || tree === void 0 ? void 0 : tree.isExpanded) {
                expanded.push(tree.id);
            }
            expanded = expanded.concat(getExpandedRecursively(tree[childrenKey]));
            setExpanded(expanded);
            firstRender.current = false;
        }
        // Do not reset expanded on subsequent updates
    }, [getExpandedRecursively, tree, childrenKey]);
    useEffect(() => {
        if (!!searchTree(tree, selectedNodeId)) {
            setIsCurrentActiveTree(true);
        }
        else {
            setIsCurrentActiveTree(false);
        }
    }, [tree, selectedNodeId]);
    const treeSelectedId = isCurrentActiveTree && selectedNodeId != null
        ? String(selectedNodeId)
        : null;
    if (!expanded) {
        return null;
    }
    return (React.createElement(TreeView, { key: tree, className: classes.root, defaultCollapseIcon: React.createElement(FluentIcon, { size: "small", component: CaretUpSolid8Icon, style: {
                color: lighten(theme.palette.primary.main, 0.5),
                width: theme.spacing(1.5),
                height: theme.spacing(1.5)
            } }), expanded: expanded || [], onNodeToggle: handleNodeExpansion, defaultExpandIcon: React.createElement(FluentIcon, { size: "small", component: CaretDownSolid8Icon, style: {
                color: lighten(theme.palette.primary.main, 0.5),
                width: theme.spacing(1.5),
                height: theme.spacing(1.5)
            } }), selected: treeSelectedId }, tree && renderTree(tree)));
};
//# sourceMappingURL=BaseTreeMenu.js.map