import React, { memo, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
import isEqual from 'lodash/isEqual';
import { ToggleButton } from './components/ToggleButton';
import { SidebarNextContext, } from './SidebarNextContext';
import { st, classes } from './SidebarNext.st.css.js';
import { dataHooks, sidebarSkins } from './constants';
import SidebarSkeleton from './components/SidebarSkeleton';
import { extractItemNodes, getItemPath, getMaxDepth, getMenuPath, pick, } from './utils';
import { useMemoizedIdentity } from './hooks/useMemoizedIdentity';
const DEFAULT_SKIN = sidebarSkins.dark;
const DEFAULT_WIDTH = 228;
const MINIMIZED_WIDTH = 54;
export const SidebarNext = memo(({ skin = DEFAULT_SKIN, width: orgWidth = DEFAULT_WIDTH, isLoading = true, dataHook, className, ariaLabel, selectedKey, header, footer, hidden = false, minimized = false, enableMinimizeToggle, minimizeToggleTooltip, onMinimizeToggleClick, zIndex, next, children, }) => {
    const [width, setWidth] = useState(minimized ? MINIMIZED_WIDTH : orgWidth);
    const [contentWidth, setContentWidth] = useState(minimized ? MINIMIZED_WIDTH : orgWidth);
    const scrollAreaRef = useRef(null);
    const structure = useMemoizedIdentity(extractItemNodes(children));
    const widthForCalc = typeof width === 'number' ? `${width}px` : width;
    const hiddenMarginLeft = `calc(-1 * ${widthForCalc})`;
    const { selectedPath, expandTrigger, isExpanded, setExpanded } = useSidebarSelectionState(selectedKey, structure);
    const maxDepth = useMemo(() => getMaxDepth(structure.items), [structure.items]);
    // Sidebar with maximum depth of 1 or 2 is styled differently (legacy mode)
    const legacy = maxDepth < 3 && !next;
    useEffect(() => {
        let timer;
        if (minimized) {
            setWidth(MINIMIZED_WIDTH);
            timer = setTimeout(() => {
                setContentWidth(MINIMIZED_WIDTH);
            }, 500);
        }
        else {
            setWidth(orgWidth);
            setContentWidth(orgWidth);
        }
        return () => {
            if (timer)
                clearTimeout(timer);
        };
    }, [minimized, orgWidth]);
    const sidebarContextValue = useMemoizedIdentity({
        skin,
        legacy,
        hidden,
        minimized,
        inert: false,
        level: 1,
        parent: 'sidebar',
        scrollAreaRef,
        selectedPath,
        expandTrigger,
        isExpanded,
        setExpanded,
    });
    return (React.createElement(SidebarNextContext.Provider, { value: sidebarContextValue },
        React.createElement("div", { className: st(classes.root, { hidden }, className), style: {
                width,
                zIndex,
                ...(hidden ? { marginLeft: hiddenMarginLeft } : {}),
            } },
            React.createElement("section", { className: st(classes.section, { skin, hidden }), "aria-label": "Sidebar" // FIXME: translations?
                , "data-hook": dataHook, "data-skin": skin, "data-hidden": hidden, "data-selected": selectedKey, "data-width": width, "data-minimized": minimized, "data-selected-key": selectedKey, "data-is-selected-expanded": isExpanded(selectedKey), "data-margin-left": hiddenMarginLeft, "data-next": next, style: { width } },
                enableMinimizeToggle && (React.createElement(ToggleButton, { minimized: minimized, minimizeToggleTooltip: minimizeToggleTooltip, onMinimizeToggleClick: onMinimizeToggleClick, skin: skin })),
                React.createElement("header", { "data-hook": dataHooks.header }, header),
                React.createElement("div", { className: classes.content },
                    React.createElement("nav", { ref: scrollAreaRef, "data-hook": dataHooks.scrollArea, className: st(classes.scrollArea, { skin }), "aria-label": ariaLabel, style: { width: contentWidth } }, isLoading ? (React.createElement("div", { style: { overflow: 'hidden' } },
                        React.createElement(SidebarSkeleton, null))) : (React.createElement("ul", { className: classes.listItems }, children)))),
                React.createElement("footer", { "data-hook": dataHooks.footer }, footer)))));
});
SidebarNext.displayName = 'SidebarNext';
const useSidebarSelectionState = (selectedKey, structure) => {
    const selectedItemPath = getItemPath(structure.keyToParentKey, selectedKey);
    const selectedMenuPath = getMenuPath(structure.keyToParentKey, selectedKey);
    const [expandedState, setExpandedState] = useState(() => ({
        expandedPath: selectedMenuPath,
        userCollapsedKeys: {},
        trigger: 'select',
    }));
    const isExpanded = useCallback((itemKey) => {
        if (itemKey === undefined) {
            return false;
        }
        const withinExpandedPath = expandedState.expandedPath.includes(itemKey);
        const collapsedByUser = expandedState.userCollapsedKeys[itemKey];
        return withinExpandedPath && !collapsedByUser;
    }, [expandedState.expandedPath, expandedState.userCollapsedKeys]);
    // We only allow toggling menus that are within the selected path. Menus
    // outside of the selected path can only be expanded by changing `selectedKey`
    // prop. This replicates previous two-level sidebar behavior.
    const setExpanded = useCallback((itemKey, expanded) => {
        setExpandedState(prev => {
            if (!prev.expandedPath.includes(itemKey)) {
                return prev;
            }
            return {
                ...prev,
                userCollapsedKeys: {
                    ...prev.userCollapsedKeys,
                    [itemKey]: !expanded,
                },
                trigger: 'click',
            };
        });
    }, []);
    // Handle `selectedKey` change
    useEffect(() => {
        if (!isEqual(expandedState.expandedPath, selectedMenuPath)) {
            setExpandedState(prev => ({
                expandedPath: selectedMenuPath,
                userCollapsedKeys: pick(prev.userCollapsedKeys, selectedMenuPath),
                trigger: 'select',
            }));
        }
    }, [expandedState.expandedPath, selectedMenuPath]);
    return {
        selectedPath: selectedItemPath,
        expandTrigger: expandedState.trigger,
        isExpanded,
        setExpanded,
    };
};
SidebarNext.displayName = 'SidebarNext';
// FIXME: prop types on memoized component
// SidebarNext.propTypes = {
//   /** The dataHook of the Sidebar */
//   dataHook: PropTypes.string,
//   /** The classes of the Sidebar */
//   className: PropTypes.string,
//   /**  Sidebar menu children */
//   children: PropTypes.node,
//   /** Sets the skin of the Sidebar */
//   skin: PropTypes.oneOf(['dark', 'light', 'neutral']),
//   /**  Renders header element */
//   header: PropTypes.node,
//   /**  Renders footer element */
//   footer: PropTypes.node,
//   /**  Controls if the sidebar is shown or hidden, using an animation to switch between the two */
//   hidden: PropTypes.bool,
//   /**  The selected item key */
//   selectedKey: PropTypes.string,
//   /**  Control whether the sidebar displays a loading animation, true by default */
//   isLoading: PropTypes.bool,
//   /** Define a string that labels the current element in case where a text label is not visible on the screen */
//   ariaLabel: PropTypes.string,
//   /**  Defines the width */
//   width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
//   /**  Enables minimized mode */
//   minimized: PropTypes.bool,
//   /**  Enables toggle button */
//   enableMinimizeToggle: PropTypes.bool,
//   /**  Defines the tooltip content of minimization toggle. */
//   minimizeToggleTooltip: PropTypes.string,
//   /**  Defines a callback function which is called every time a minimize toggle button is clicked. */
//   onMinimizeToggleClick: PropTypes.func,
// };
//# sourceMappingURL=SidebarNextNext.js.map