import React, { Component, cloneElement } from 'react';
import { st, classes } from './Sidebar.st.css.js';
import { SidebarItem } from './SidebarItem';
import { SidebarPersistentHeader } from './SidebarPersistentHeader';
import { SidebarPersistentFooter } from './SidebarPersistentFooter';
import { SidebarBackButton } from './SidebarBackButton';
import { SidebarContext } from './SidebarAPI';
import { dataHooks, sidebarSkins } from './constants';
import { SidebarContentWrapper } from './SidebarContentWrapper';
import { WixDesignSystemContext } from '../WixDesignSystemProvider/context';
const CollapsibeInnerMenuOpenChildren = props => {
    const { children, waitForOtherMenuToClose, skin, isAlreadyOpen } = props;
    return (React.createElement("div", { "data-hook": "open-inner-menu-children", className: isAlreadyOpen
            ? ''
            : st(waitForOtherMenuToClose
                ? classes.innerMenuWrapperInToPlaceAfterClosingOther
                : classes.innerMenuWrapperInToPlace) },
        React.createElement(SidebarContentWrapper, { containerClasses: st(classes.innerMenu), containerDataHook: dataHooks.drivenInChildren, skin: skin }, children)));
};
const CollapsibeInnerMenuCloseChildren = props => {
    const { children } = props;
    return (React.createElement("div", { "data-hook": "closed-inner-menu-children", className: st(classes.innerMenuWrapperOutOfPlace) },
        React.createElement("div", { className: st(classes.innerMenu), "data-hook": dataHooks.drivenOutChildren }, children)));
};
const CollapsibeInnerMenuCloseParent = props => {
    const { isAlreadyClosed, children } = props;
    const closeParentClass = st(isAlreadyClosed ? classes.closedInnerMenu : classes.closingInnerMenu);
    return (React.createElement("div", { "data-hook": "closed-inner-menu", className: closeParentClass }, children));
};
const CollapsibeInnerMenuOpenParent = props => {
    const { isAlreadyOpen, children, waitForOtherMenuToClose } = props;
    const openParentClass = waitForOtherMenuToClose
        ? st(classes.openingInnerMenuAfterClosingOther)
        : st(isAlreadyOpen ? classes.openInnerMenu : classes.openingInnerMenu);
    return (React.createElement("div", { "data-hook": "open-inner-menu", className: openParentClass }, children));
};
/** A sidebar navigation component  */
class Sidebar extends Component {
    constructor(props) {
        super(props);
        this._getInnerMenuCollapsibleState = options => {
            const { menuToClose, menuToOpen, selected } = options;
            let expandedInnerMenu;
            const openMenuChildren = this.itemKeyToChildren[menuToOpen] &&
                (this.itemKeyToChildren[menuToOpen].children || []);
            const closeMenuChildren = this.itemKeyToChildren[menuToClose] &&
                (this.itemKeyToChildren[menuToClose].children || []);
            const collapsibleOnScreenChildren = this.firstLevelItems.reduce((accumulator, child) => {
                const shouldExpand = menuToOpen &&
                    child.props.itemKey === menuToOpen &&
                    openMenuChildren.length > 0;
                const shouldCollapse = this.state.expandedInnerMenu &&
                    menuToClose &&
                    closeMenuChildren.length > 0 &&
                    child.props.itemKey === menuToClose &&
                    this.state.expandedInnerMenu === menuToClose;
                const waitForOtherMenuToClose = this.state.expandedInnerMenu &&
                    menuToClose &&
                    this.state.expandedInnerMenu === menuToClose &&
                    menuToClose !== menuToOpen;
                if (shouldExpand) {
                    expandedInnerMenu = menuToOpen;
                    return [
                        ...accumulator,
                        React.createElement(CollapsibeInnerMenuOpenParent, { key: `open-parent-${menuToOpen}`, isAlreadyOpen: this._isAlreadyOpen(menuToOpen), waitForOtherMenuToClose: waitForOtherMenuToClose }, child),
                        React.createElement(CollapsibeInnerMenuOpenChildren, { key: `open-children-${menuToOpen}`, waitForOtherMenuToClose: waitForOtherMenuToClose, skin: this.props.skin, isAlreadyOpen: this._isAlreadyOpen(menuToOpen) }, openMenuChildren),
                    ];
                }
                if (shouldCollapse) {
                    return [
                        ...accumulator,
                        React.createElement(CollapsibeInnerMenuCloseParent, { key: `closed-parent-${menuToClose}`, isAlreadyClosed: this._isAlreadyClosed(selected, menuToClose) }, child),
                        React.createElement(CollapsibeInnerMenuCloseChildren, { key: `closed-children-${menuToClose}` }, closeMenuChildren),
                    ];
                }
                return [...accumulator, child];
            }, []);
            return {
                collapsibleOnScreenChildren,
                expandedInnerMenu,
            };
        };
        this._shouldCollapseInnerMenu = itemKey => this.state.expandedInnerMenu === itemKey &&
            ((itemKey === this.state.selectedKey && this.state.expandedInnerMenu) ||
                itemKey !== this.state.selectedKey);
        this._shouldExpandInnerMenu = (parentKey, itemKey) => (parentKey === this.state.lastSelectedKey &&
            !this.state.expandedInnerMenu) ||
            this.itemKeyToParentKey[itemKey] === parentKey ||
            parentKey !== this.state.lastSelectedKey;
        this._navigateTo = itemKey => {
            if (this._isChild(itemKey)) {
                this._selectItem(itemKey);
                this.sidebarContext = this._getSidebarContext();
                return;
            }
            if (this._isParent(itemKey)) {
                this._openInnerMenu(itemKey);
                this.sidebarContext = this._getSidebarContext();
                return;
            }
            if (itemKey) {
                this._closeInnerMenu(itemKey);
                this.sidebarContext = this._getSidebarContext();
                return;
            }
        };
        this._getSidebarContext = () => {
            return {
                itemClicked: this._navigateTo,
                backClicked: () => {
                    this._closeInnerMenu();
                    this.sidebarContext = this._getSidebarContext();
                },
                getSelectedKey: () => this.state.selectedKey,
                getSkin: () => this.props.skin,
                getIsMenuExpanded: () => this.state.expandedInnerMenu,
            };
        };
        this.sidebarContext = this._getSidebarContext();
        this._getInnerChildSelectedState = itemKey => {
            const collapsibleInnerMenuState = this._getInnerMenuCollapsibleState({
                menuToClose: this.state.lastSelectedKey,
                menuToOpen: this.itemKeyToParentKey[itemKey],
                selected: itemKey,
            });
            if (this.itemKeyToParentKey[itemKey] !== this.state.lastSelectedKey) {
                return {
                    drivenInChildren: this.itemKeyToChildren[this.itemKeyToParentKey[itemKey]].children,
                    selectedKey: itemKey,
                    lastSelectedKey: this.itemKeyToParentKey[itemKey],
                    ...collapsibleInnerMenuState,
                };
            }
            else {
                return {
                    ...collapsibleInnerMenuState,
                    selectedKey: itemKey,
                };
            }
        };
        this._getInnerMenuOpenState = itemKey => {
            const { children, selectedKey } = this.itemKeyToChildren[itemKey];
            const selected = this.itemKeyToParentKey[this.state.lastSelectedKey] === itemKey
                ? this.state.lastSelectedKey
                : selectedKey;
            const parentKey = this.itemKeyToParentKey[selected];
            const parentItemKeyToOpen = this._getItemToOpenKey(parentKey, itemKey);
            const parentItemKeyToClose = this._getItemToCloseKey(this.state.lastSelectedKey);
            return {
                ...this._getInnerMenuCollapsibleState({
                    menuToClose: parentItemKeyToClose,
                    menuToOpen: parentItemKeyToOpen,
                    selected,
                }),
                drivenInChildren: children,
                drivenOutChildren: [],
                selectedKey: selected,
                lastSelectedKey: itemKey,
            };
        };
        this._getItemToCloseKey = itemKey => {
            if (this._shouldCollapseInnerMenu(itemKey)) {
                return this.itemKeyToParentKey[itemKey] || itemKey;
            }
            if (this._shouldCollapseInnerMenu(this.state.lastSelectedKey)) {
                return (this.itemKeyToParentKey[this.state.lastSelectedKey] ||
                    this.state.lastSelectedKey);
            }
            return undefined;
        };
        this._getItemToOpenKey = (parentKey, itemKey) => this._shouldExpandInnerMenu(parentKey, itemKey) ? parentKey : undefined;
        this._getInnerMenuCloseState = (itemKey, updateCollapsibleOnlyOnChange) => {
            const selectedKey = this.state.lastSelectedKey || itemKey;
            const parentItemKeyToClose = this._getItemToCloseKey(selectedKey);
            return {
                ...this._getInnerMenuCollapsibleState({
                    menuToClose: parentItemKeyToClose,
                    selected: selectedKey,
                }),
                selectedKey: itemKey || this.state.lastSelectedKey,
                lastSelectedKey: selectedKey,
                drivenInChildren: [],
                drivenOutChildren: this.state.drivenInChildren,
            };
        };
        this._getItemWithKey = (item, itemKey) => item.props.itemKey ? item : cloneElement(item, { ...item.props, itemKey });
        this._getChildrenWithKeys = child => (child.props.innerMenu &&
            child.props.innerMenu.map((innerChild, index) => this._getItemWithKey(innerChild, child.props.itemKey + index))) ||
            [];
        this._isParent = itemKey => this.itemKeyToChildren[itemKey];
        this._isChild = itemKey => this.itemKeyToParentKey[itemKey];
        this._isAlreadyOpen = menuToOpen => this.state.lastSelectedKey === menuToOpen &&
            this.itemKeyToParentKey[this.props.selectedKey] === menuToOpen &&
            this.state.expandedInnerMenu === menuToOpen;
        this._isAlreadyClosed = (selected, menuToClose) => this.itemKeyToParentKey[selected] !== menuToClose;
        this._selectItem = itemKey => this.setState(this._getInnerChildSelectedState(itemKey));
        this._openInnerMenu = itemKey => this.setState(this._getInnerMenuOpenState(itemKey));
        this._closeInnerMenu = itemKey => this.setState(this._getInnerMenuCloseState(itemKey));
        this.itemKeyToChildren = {};
        this.itemKeyToParentKey = {};
        this.firstLevelItems = [];
        this.state = {
            persistentTopChildren: [],
            drivenOutChildren: [],
            onScreenChildren: [],
            collapsibleOnScreenChildren: [],
            drivenInChildren: [],
            persistentBottomChildren: [],
            selectedKey: '',
            lastSelectedKey: '',
            expandedInnerMenu: undefined,
        };
    }
    UNSAFE_componentWillMount() {
        this._setInnerMenus(this.props);
    }
    UNSAFE_componentWillReceiveProps(props) {
        this._setInnerMenus(props);
    }
    _setInnerMenus(props) {
        const persistentTopChildren = [];
        const persistentBottomChildren = [];
        const onScreenChildren = [];
        const findEnabledChild = item => item.props.innerMenu &&
            item.props.innerMenu.find(c => c.type === SidebarItem && !c.props.disable);
        const handleChild = child => {
            if (child.type === SidebarItem) {
                const enabledChild = findEnabledChild(child);
                const innerChildrenWithKeys = this._getChildrenWithKeys(child);
                this.itemKeyToChildren[child.props.itemKey] = {
                    selectedKey: enabledChild
                        ? enabledChild.props.itemKey
                        : child.props.itemKey,
                    children: innerChildrenWithKeys,
                };
                if (child.props.innerMenu) {
                    innerChildrenWithKeys.forEach(innerChild => {
                        if (innerChild.type !== SidebarBackButton) {
                            this.itemKeyToParentKey[innerChild.props.itemKey] =
                                child.props.itemKey;
                        }
                    });
                }
                onScreenChildren.push(child);
            }
            else if (child.type === SidebarPersistentHeader) {
                persistentTopChildren.push(child);
            }
            else if (child.type === SidebarPersistentFooter) {
                persistentBottomChildren.push(child);
            }
            else {
                onScreenChildren.push(child);
            }
        };
        if (props.children) {
            if (props.children.length) {
                props.children.forEach(child => {
                    if (child) {
                        if (child.length > 0) {
                            child.forEach(handleChild);
                        }
                        else {
                            handleChild(child);
                        }
                    }
                });
            }
            else {
                handleChild(props.children);
            }
        }
        this.firstLevelItems = onScreenChildren.slice();
        const newState = {
            persistentTopChildren,
            persistentBottomChildren,
            onScreenChildren,
            selectedKey: props.selectedKey,
        };
        const selectedItemParentKey = this.itemKeyToParentKey[props.selectedKey];
        if (selectedItemParentKey) {
            this.setState({
                ...newState,
                drivenInChildren: this.itemKeyToChildren[selectedItemParentKey].children,
                lastSelectedKey: selectedItemParentKey,
                ...this._getInnerMenuCollapsibleState({
                    menuToClose: this.itemKeyToParentKey[this.props.selectedKey] ||
                        this.props.selectedKey,
                    menuToOpen: selectedItemParentKey,
                    selected: props.selectedKey,
                }),
            });
        }
        else {
            const updateCollapsibleOnlyOnChange = true;
            this.setState({
                ...newState,
                drivenInChildren: [],
                ...this._getInnerMenuCloseState(props.selectedKey, updateCollapsibleOnlyOnChange),
            });
        }
    }
    render() {
        const { isHidden, skin } = this.props;
        const css = { ...classes, ...this.props.classNames };
        const sliderClasses = st(css.slider, {
            skin,
        }, this.state.drivenInChildren.length !== 0 && css.sliderOutToLeft, this.state.drivenInChildren.length === 0 &&
            this.state.drivenOutChildren.length !== 0 &&
            css.sliderInFromLeft);
        const collapsibleSliderClasses = st(css.slider, {
            skin,
        });
        const sliderOutToRightClasses = st(css.slider, {
            skin,
        }, !this.props.isHidden && css.sliderOutToRight);
        const sliderInFromRightClasses = st(css.slider, {
            skin,
        }, !this.props.isHidden && css.sliderInFromRight);
        const rootClasses = st(css.sideBar || classes.root, {
            hidden: isHidden,
            skin,
        });
        return (React.createElement(WixDesignSystemContext.Consumer, null, ({ sidebarExperimentCollapsible }) => {
            return (React.createElement(SidebarContext.Provider, { value: this.sidebarContext },
                React.createElement("div", { className: rootClasses, "data-hook": this.props.dataHook, "data-skin": skin },
                    this.state.persistentTopChildren,
                    React.createElement("div", { className: st(css.content) },
                        !sidebarExperimentCollapsible &&
                            this.state.drivenInChildren.length === 0 &&
                            this.state.drivenOutChildren.length !== 0 && (React.createElement("div", { className: sliderOutToRightClasses, "data-hook": dataHooks.drivenOutChildren }, this.state.drivenOutChildren)),
                        React.createElement(SidebarContentWrapper, { containerClasses: sidebarExperimentCollapsible
                                ? collapsibleSliderClasses
                                : sliderClasses, skin: skin }, sidebarExperimentCollapsible
                            ? this.state.collapsibleOnScreenChildren
                            : this.state.onScreenChildren),
                        !sidebarExperimentCollapsible &&
                            this.state.drivenInChildren.length !== 0 && (React.createElement(SidebarContentWrapper, { key: "collapsiblle", containerClasses: sliderInFromRightClasses, containerDataHook: dataHooks.drivenInChildren, skin: skin }, this.state.drivenInChildren))),
                    this.state.persistentBottomChildren)));
        }));
    }
}
Sidebar.displayName = 'Sidebar';
Sidebar.Item = SidebarItem;
Sidebar.PersistentHeader = SidebarPersistentHeader;
Sidebar.PersistentFooter = SidebarPersistentFooter;
Sidebar.BackButton = SidebarBackButton;
Sidebar.defaultProps = {
    skin: sidebarSkins.dark,
    isHidden: false,
};
export default Sidebar;
//# sourceMappingURL=Sidebar.js.map