import React from 'react';
import { st, classes } from './ComposerSidebar.st.css.js';
import { dataHooks } from './constants';
import Box from '../Box';
import ToggleButton from '../ToggleButton';
import Text from '../Text';
const isItemEnabled = item => !item.disabled;
const getNextEnabledIndex = (items, currentIndex, direction) => {
    const len = items.length;
    let next = (currentIndex + direction + len) % len;
    let steps = 0;
    while (steps < len && !isItemEnabled(items[next])) {
        next = (next + direction + len) % len;
        steps++;
    }
    return steps < len ? next : currentIndex;
};
const getFirstEnabledIndex = items => {
    for (let i = 0; i < items.length; i++) {
        if (isItemEnabled(items[i]))
            return i;
    }
    return -1;
};
const getLastEnabledIndex = items => {
    for (let i = items.length - 1; i >= 0; i--) {
        if (isItemEnabled(items[i]))
            return i;
    }
    return -1;
};
const getPreferredFocusIndex = (items, selectedIndex) => {
    if (items.length === 0)
        return -1;
    const preferred = Math.min(selectedIndex, items.length - 1);
    return isItemEnabled(items[preferred])
        ? preferred
        : getFirstEnabledIndex(items);
};
/** ComposerSidebar */
class ComposerSidebar extends React.PureComponent {
    constructor() {
        super(...arguments);
        this.state = { focusedIndex: null };
        this._sectionContainerRef = React.createRef();
        this._itemRefs = {};
        this._getSelectedIndex = () => {
            const { items, selectedId } = this.props;
            if (selectedId == null)
                return 0;
            const index = items.findIndex(item => item.id === selectedId);
            return index >= 0 ? index : 0;
        };
        this._getEffectiveFocusedIndex = () => {
            const { items } = this.props;
            const { focusedIndex } = this.state;
            if (items.length === 0)
                return -1;
            if (focusedIndex !== null)
                return focusedIndex;
            return getPreferredFocusIndex(items, this._getSelectedIndex());
        };
        this._handleKeyDown = e => {
            const { items } = this.props;
            if (items.length === 0)
                return;
            const effectiveIndex = this._getEffectiveFocusedIndex();
            const currentIndex = effectiveIndex >= 0 ? effectiveIndex : getFirstEnabledIndex(items);
            let nextIndex = currentIndex;
            switch (e.key) {
                case 'ArrowDown':
                    nextIndex = getNextEnabledIndex(items, currentIndex, 1);
                    break;
                case 'ArrowUp':
                    nextIndex = getNextEnabledIndex(items, currentIndex, -1);
                    break;
                case 'Home':
                    nextIndex = getFirstEnabledIndex(items);
                    break;
                case 'End':
                    nextIndex = getLastEnabledIndex(items);
                    break;
                default:
                    return;
            }
            if (nextIndex !== -1 &&
                nextIndex !== currentIndex &&
                isItemEnabled(items[nextIndex])) {
                this.setState({ focusedIndex: nextIndex }, () => {
                    const itemEl = this._itemRefs[nextIndex];
                    itemEl?.querySelector?.('button')?.focus();
                });
                e.preventDefault();
            }
        };
        this._handleFocusOut = e => {
            const container = this._sectionContainerRef.current;
            if (!container)
                return;
            const relatedTarget = e.relatedTarget;
            if (!relatedTarget || container.contains(relatedTarget))
                return;
            this.setState({ focusedIndex: null });
        };
        this._renderSection = ({ section: { items: sectionItems, sectionTitle }, showSectionTitles = false, }) => {
            const { selectedId, labelPlacement } = this.props;
            return (React.createElement(React.Fragment, null,
                showSectionTitles ? (React.createElement(Text, { className: classes.title, size: "small", weight: "bold", ellipsis: true }, sectionTitle ?? 'Undefined')) : null,
                React.createElement("ul", { role: "menu", "data-hook": "composer-sidebar-items-container", "data-selected-id": selectedId, "data-label-placement": labelPlacement, className: classes.itemsContainer }, sectionItems.map(item => this._renderItem(item)))));
        };
        this._renderSections = sections => {
            const { labelPlacement, size, width } = this.props;
            const withSections = sections.length > 1 ||
                (sections.length === 1 && sections[0].sectionTitle);
            return (React.createElement("div", { ref: this._sectionContainerRef, role: withSections ? 'menu' : undefined, direction: "vertical", onKeyDown: this._handleKeyDown, onBlur: this._handleFocusOut, className: st(classes.sectionContainer, {
                    withSections,
                    labelPlacement,
                    size,
                }), style: width ? { width } : undefined }, withSections
                ? sections.map((section, index) => (React.createElement("div", { key: index, role: "menuitem", className: classes.section }, this._renderSection({
                    section,
                    showSectionTitles: true,
                }))))
                : this._renderSection({ section: sections[0] })));
        };
        this._separateToSections = items => {
            const sectionTitles = Array.from(new Set(items.map(({ sectionTitle }) => sectionTitle ? sectionTitle : undefined)));
            const sections = sectionTitles.map(sectionTitle => ({
                sectionTitle,
                items: items.filter(({ sectionTitle: itemSectionTitle }) => (!sectionTitle && !itemSectionTitle) ||
                    sectionTitle === itemSectionTitle),
            }));
            return sections;
        };
    }
    _renderItem(item) {
        const { items, selectedId, labelPlacement, size, onClick, className, labelTooltipProps, ellipsis, } = this.props;
        const { label, id, icon, disabled, sectionTitle, ...rest } = item;
        const itemIndex = items.findIndex(i => i.id === id);
        const selected = selectedId === id;
        const onClickHandler = item.onClick || onClick;
        const effectiveFocusedIndex = this._getEffectiveFocusedIndex();
        const isFocused = effectiveFocusedIndex === itemIndex;
        return (React.createElement("li", { ref: el => {
                this._itemRefs[itemIndex] = el;
            }, role: "menuitem", "data-hook": `composer-sidebar-item-container-${id}`, key: `sidebar-item-${id}`, "data-section-title": sectionTitle, className: st(classes.item, { labelPlacement, size }, className) },
            React.createElement(ToggleButton, { ...rest, tabIndex: isFocused ? 0 : -1, onFocus: () => this.setState({ focusedIndex: itemIndex }), className: st(classes.sidebarItemButton, { labelPlacement, size }), dataHook: `composer-sidebar-item-${id}`, onClick: e => onClickHandler(e, { id, label }), shape: "round", size: size, border: true, skin: "inverted", labelEllipsis: ellipsis, disabled: disabled, selected: selected, labelValue: label, labelPlacement: labelPlacement, tooltipProps: labelTooltipProps }, icon)));
    }
    render() {
        const { items, className, dataHook, labelPlacement, width } = this.props;
        const sections = this._separateToSections(items);
        return (React.createElement(Box, { height: "100%", maxHeight: "100%", width: width, className: st(classes.root, { labelPlacement }, className), dataHook: dataHook || dataHooks.composerSidebarContainer }, sections.length ? this._renderSections(sections) : null));
    }
}
ComposerSidebar.displayName = 'ComposerSidebar';
ComposerSidebar.defaultProps = {
    labelPlacement: 'end',
    selectedId: null,
    items: [],
    size: 'medium',
    onClick: () => { },
    labelTooltipProps: {
        placement: 'right',
    },
    ellipsis: true,
};
export default ComposerSidebar;
//# sourceMappingURL=ComposerSidebar.js.map