import React, { ElementType, forwardRef, useMemo } from 'react';
import { Menu, Transition } from '@headlessui/react';
import styles from './dropdown.module.css';
import classNames from 'classnames';
import DropdownItem from '@/components/elements/dropdown/DropdownItem';
import DropdownButton from '@/components/elements/dropdown/DropdownButton';

interface Props {
    as?: ElementType;
    children: React.ReactNode;
}

const DropdownGap = ({ invisible }: { invisible?: boolean }) => (
    <div className={classNames('border m-2', { 'border-neutral-700': !invisible, 'border-transparent': invisible })}/>
);

type TypedChild = (React.ReactChild | React.ReactFragment | React.ReactPortal) & {
    type?: JSX.Element;
}

const Dropdown = forwardRef<typeof Menu, Props>(({ as, children }, ref) => {
    const [ Button, items ] = useMemo(() => {
        const list = React.Children.toArray(children) as unknown as TypedChild[];

        return [
            list.filter(child => child.type === DropdownButton),
            list.filter(child => child.type !== DropdownButton),
        ];
    }, [ children ]);

    if (!Button) {
        throw new Error('Cannot mount <Dropdown /> component without a child <Dropdown.Button />.');
    }

    return (
        <Menu as={as || 'div'} className={styles.menu} ref={ref}>
            {Button}
            <Transition
                enter={'transition duration-100 ease-out'}
                enterFrom={'transition scale-95 opacity-0'}
                enterTo={'transform scale-100 opacity-100'}
                leave={'transition duration-75 ease-out'}
                leaveFrom={'transform scale-100 opacity-100'}
                leaveTo={'transform scale-95 opacity-0'}
            >
                <Menu.Items className={classNames(styles.items_container, 'w-56')}>
                    <div className={'px-1 py-1'}>
                        {items}
                    </div>
                </Menu.Items>
            </Transition>
        </Menu>
    );
});

const _Dropdown = Object.assign(Dropdown, {
    Button: DropdownButton,
    Item: DropdownItem,
    Gap: DropdownGap,
});

export { _Dropdown as default };
