import {useState, useRef, HTMLAttributes, useEffect, CSSProperties} from 'react';
import cls from 'classnames';
import {IconType, Icon} from '@core0/icon';
import {Popover} from '@core0/popover';
import {Transition} from '@core0/transition';
import {Tooltip} from '@core0/tooltip';
import cn from './dropdown.module.styl';

export interface DropdownItem<T = unknown> {
    iconName?: IconType;
    imgName?: string;
    text: string;
    reactKey: string;
    value: T;
    tooltip?: string;
}

export interface DropdownProps<T = unknown> extends Pick<HTMLAttributes<HTMLDivElement>, 'className' | 'style'> {
    onActiveItemChange(evt: DropdownItem<T>): void;
    withArrow?: boolean;
    placeholder?: string;
    disabled?: boolean;
    list: DropdownItem<T>[];
    activeItem?: DropdownItem<T>;
    comparableItem?: DropdownItem<T>;
    padding?: number;
    height?: number;
    roundCorner?: boolean;
    maxViewableItems?: number;
    textAlign?: CSSProperties['textAlign'];
    justifyContent?: CSSProperties['justifyContent'];
    iconFontSize?: CSSProperties['fontSize'];
}

export function Dropdown<T = unknown>(props: DropdownProps<T>): JSX.Element {
    const {
        onActiveItemChange,
        list,
        activeItem,
        comparableItem,
        className,
        style,
        maxViewableItems,
        textAlign,
        justifyContent,
        iconFontSize,
        withArrow = true,
        disabled = false,
        placeholder = 'Please select…',
        padding = 15,
        height = 40,
        roundCorner = false
    } = props;

    const hostElmRef = useRef<HTMLDivElement>(null);
    const popoverElmRef = useRef<HTMLUListElement>(null);
    const sortedList: DropdownItem<T>[] = deriveSortedList();
    const [popoverAnchorElmDOMRect, setPopoverAnchorElmDOMRect] = useState<DOMRect>();

    const isPopoverActive = !!popoverAnchorElmDOMRect;
    const isListEmpty: boolean = list.length === 0;

    /*
     ****************************************
     * Effect Hooks
     ****************************************
     */
    useEffect(() => {
        if (!popoverAnchorElmDOMRect || !popoverElmRef.current) return;
        popoverElmRef.current.style.width = `${popoverAnchorElmDOMRect.width}px`;
    }, [popoverAnchorElmDOMRect]);

    /*
     ****************************************
     * Event Handlers
     ****************************************
     */
    function hostElmClickHandler() {
        if (hostElmRef?.current) {
            setPopoverAnchorElmDOMRect(hostElmRef.current.getBoundingClientRect());
        }
    }

    function popoverCloseHandler() {
        setPopoverAnchorElmDOMRect(undefined);
    }

    function dropdownItemClickHandler(item: DropdownItem<T>) {
        setPopoverAnchorElmDOMRect(undefined);
        if (item !== activeItem) onActiveItemChange(item);
    }

    function deriveSortedList(): DropdownItem<T>[] {
        const found = list.find((elm) => elm === activeItem);
        const rest = [...list.filter((elm) => elm !== activeItem)].filter((elm) => elm);
        return found ? [found, ...rest] : rest;
    }

    return (
        <>
            <div
                ref={hostElmRef}
                className={cls(cn.ffwdDropdown, className, {
                    [cn.disabled]: disabled,
                    [cn.comparison]: comparableItem && comparableItem === activeItem
                })}
                style={{
                    ...style,
                    height,
                    borderRadius: roundCorner ? height / 2 : undefined,
                    paddingLeft: padding,
                    paddingRight: padding,
                    textAlign,
                    justifyContent
                }}
                onClick={hostElmClickHandler}
            >
                {!activeItem && placeholder && (
                    <>
                        <span className={cn.label}>{placeholder}</span>
                        {withArrow && <Icon className={cn.icon} type="down" />}
                    </>
                )}
                {activeItem && (
                    <>
                        {activeItem?.imgName ? (
                            activeItem.imgName === 'placeholder' ? (
                                <i className={cn.activeIconPlaceholder} />
                            ) : (
                                <img className={cn.activeIcon} src={activeItem.imgName} alt={activeItem.text} />
                            )
                        ) : null}
                        {activeItem?.iconName && (
                            <Icon className={cn.icon} type={activeItem.iconName} style={{fontSize: iconFontSize}} />
                        )}
                        {activeItem?.text && <span className={cn.label}>{activeItem?.text}</span>}
                        {withArrow && <Icon className={cls(cn.icon, cn.down)} type="down" />}
                    </>
                )}
            </div>
            {!isListEmpty && isPopoverActive && (
                <Popover
                    anchorRect={popoverAnchorElmDOMRect}
                    verticalAlign="popover-top-to-anchor-top"
                    horizontalAlign="popover-left-to-anchor-left"
                    onClose={popoverCloseHandler}
                >
                    <ul
                        ref={popoverElmRef}
                        className={cn.ffwdDropdownPopover}
                        style={{
                            borderRadius: roundCorner ? height / 2 : undefined,
                            maxHeight: maxViewableItems ? maxViewableItems * height : undefined,
                            overflow: maxViewableItems ? 'auto' : undefined
                        }}
                    >
                        {sortedList.map((elm, idx) => (
                            <Transition disabled={idx === 0} key={elm.reactKey}>
                                <li
                                    className={cls(cn.listItem, {[cn.active]: elm === activeItem, [cn.comparison]: elm === comparableItem})}
                                    style={{
                                        height,
                                        paddingLeft: padding,
                                        paddingRight: padding,
                                        textAlign,
                                        justifyContent
                                    }}
                                    onClick={() => dropdownItemClickHandler(elm)}
                                >
                                    {elm.imgName ? (
                                        elm.imgName === 'placeholder' ? (
                                            <i className={cn.iconPlaceholder} />
                                        ) : (
                                            <img className={cn.iconImg} src={elm.imgName} alt={elm.text} />
                                        )
                                    ) : null}
                                    {elm.iconName && (
                                        <Icon className={cn.icon} type={elm.iconName} style={{fontSize: iconFontSize}} />
                                    )}
                                    {elm.text && <span className={cn.label}>{elm.text}</span>}
                                    {elm === activeItem && withArrow && <Icon className={cls(cn.icon, cn.up)} type="up" />}
                                    {elm.tooltip && <Tooltip>{elm.tooltip}</Tooltip>}
                                </li>
                            </Transition>
                        ))}
                    </ul>
                </Popover>
            )}
        </>
    );
}
