import { MoreVerticalIcon } from '@fluentui/react-icons';
import { MenuItem, Popover } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import PropTypes from 'prop-types';
import React, { Children, cloneElement, forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { useDynamicListCalculation } from '../../hooks/useDynamicListCalculation';
import { AmbientTokenButton } from '../inputs/buttons/AmbientTokenButton';
const useStyles = makeStyles((theme) => ({
    filterChipMenuIcon: {
        background: theme.palette.common.grey,
        padding: theme.spacing(1),
        color: theme.palette.primary.main
    }
}));
export const DynamicContainerWithMenu = forwardRef((props, ref) => {
    // ################### Props ###################
    const { children, className, menuButton, menuIconClassName, includeBuffer = true } = props;
    // ################### Custom Hooks ###################
    const classes = useStyles();
    const { calculateNumberOfVisibleChildren } = useDynamicListCalculation();
    // ################### Memoized Values ###################
    const modifiedMenuButton = useMemo(() => {
        if (!menuButton)
            return null;
        return cloneElement(menuButton, Object.assign({ onClick: (event) => {
                menuButton.props.onClick(event);
                handlePopoverClick(event);
            } }, menuButton.props), menuButton.props.children);
    }, [menuButton]);
    // ################### States ###################
    const [allChildren, setAllChildren] = useState([]);
    const [visibleChildren, setVisibleChildren] = useState([]);
    const [menuChildren, setMenuChildren] = useState([]);
    const [anchorEl, setAnchorEl] = useState(null);
    // ################### Variables ###################
    const open = Boolean(anchorEl);
    const id = open ? 'simple-popover' : undefined;
    // ################### Refs ###################
    const containerRef = useRef(ref);
    const outerContainerRef = useRef(null);
    const childrenRefs = useRef([]);
    // ################### Functions ###################
    const handlePopoverClick = (event) => {
        setAnchorEl(event.currentTarget);
    };
    const handlePopoverClose = () => {
        setAnchorEl(null);
    };
    // ################### Callbacks ###################
    const handleSizeChange = useCallback(() => {
        const maxVisibleChildren = calculateNumberOfVisibleChildren(containerRef, childrenRefs, includeBuffer);
        const visibleChildren = allChildren.slice(0, maxVisibleChildren);
        const menuChildren = allChildren.slice(maxVisibleChildren);
        setVisibleChildren(visibleChildren);
        setMenuChildren(menuChildren);
    }, [
        containerRef,
        allChildren,
        childrenRefs,
        calculateNumberOfVisibleChildren,
        includeBuffer
    ]);
    const handleMenuItemClick = useCallback((child) => {
        if (child.props.onClick && typeof child.props.onClick === 'function') {
            child.props.onClick();
        }
        // If the child has children, then call the onClick function for each child
        let children = child.props.children;
        while (children) {
            if (Array.isArray(children) && children.length > 0) {
                children.forEach((child) => {
                    if (child.props.onClick &&
                        typeof child.props.onClick === 'function') {
                        child.props.onClick();
                    }
                });
            }
            else if (typeof children === 'object') {
                if (children.props.onClick &&
                    typeof children.props.onClick === 'function') {
                    children.props.onClick();
                }
            }
            children = children.props.children;
        }
        handlePopoverClose();
    }, []);
    // ################### Effects ###################
    useEffect(() => {
        const arrayChildren = Children.toArray(children);
        setAllChildren(arrayChildren);
        setVisibleChildren(arrayChildren);
    }, [children]);
    useLayoutEffect(handleSizeChange, [handleSizeChange]);
    useLayoutEffect(() => {
        // Add the resize event listener for when the browser window is resized
        window.addEventListener('resize', handleSizeChange);
        // Add the resize observer for when the parent div is resized
        const resizeObserver = new ResizeObserver(handleSizeChange);
        if (outerContainerRef.current) {
            resizeObserver.observe(outerContainerRef.current);
        }
        // Remove the event listeners on cleanup
        return () => {
            window.removeEventListener('resize', handleSizeChange);
            resizeObserver.disconnect();
        };
    }, [handleSizeChange, outerContainerRef]);
    // ################### Render ###################
    return (React.createElement("div", { ref: outerContainerRef, style: {
            width: '100%',
            overflow: 'hidden'
        } }, React.createElement("div", { className: className, ref: containerRef, style: {
            display: 'flex',
            flexWrap: 'noWrap',
            overflow: 'hidden',
            flexGrow: 1
        } }, visibleChildren &&
        Children.map(visibleChildren, (child, index) => {
            return cloneElement(child, Object.assign({ ref: (ref) => (childrenRefs.current[index] = ref) }, child.props), child.props.children);
        }), menuChildren && menuChildren.length > 0 && (React.createElement("div", null, modifiedMenuButton !== null && modifiedMenuButton !== void 0 ? modifiedMenuButton : (React.createElement(AmbientTokenButton, { id: id, icon: MoreVerticalIcon, tooltip: "Additional Filter Values", ariaLabel: "Additional Filter Values", onClick: handlePopoverClick, iconClassName: menuIconClassName !== null && menuIconClassName !== void 0 ? menuIconClassName : classes.filterChipMenuIcon })), React.createElement(Popover, { id: id, open: open, anchorEl: anchorEl, onClose: handlePopoverClose, anchorOrigin: {
            vertical: 'bottom',
            horizontal: 'right'
        }, transformOrigin: {
            vertical: 'top',
            horizontal: 'right'
        } }, Children.map(menuChildren, (child, index) => {
        return (React.createElement(MenuItem, { onClick: () => handleMenuItemClick(child) }, cloneElement(child, Object.assign({}, child.props), child.props.children)));
    })))))));
});
DynamicContainerWithMenu.displayName = 'DynamicContainerWithMenu';
DynamicContainerWithMenu.propTypes = {
    /**
     * The children to render in the container
     */
    children: PropTypes.node.isRequired,
    /**
     * A className to apply to the container
     */
    className: PropTypes.string,
    /**
     * A custom menu button to use instead of the default
     */
    menuButton: PropTypes.node,
    /**
     * A custom class to apply to the menu icon
     */
    menuIconClassName: PropTypes.string,
    /**
     * Whether to include a space buffer between the menu button and container border (default: true)
     * @default true
     */
    includeBuffer: PropTypes.bool
};
//# sourceMappingURL=DynamicContainerWithMenu.js.map