import React, { useRef, useCallback, useState } from 'react';
import useClickOutside from 'utils/useClickOutside';
import useRotate from 'styles/animation/useRotate';
import { animated, useTransition } from 'react-spring';
import { Wrapper, DownIcon, Menu, MenuItem } from './style';
import { IDropdown, IValue } from './types';

const Down = animated(DownIcon);
const AnimatedMenu = animated(Menu);

const isSelected = (selected: IValue, current: number | string) => {
    if (Array.isArray(selected)) {
        return selected.includes(current);
    } else {
        return selected === current;
    }
};

export const Dropdown = function({
    content,
    trigger,
    options,
    overlay,
    onChange,
    position,
    children,
    visible,
    onVisibleChange,
    value,
    defaultValue,
    toggle = false,
    multiple = false,
    indicator = false,
    width = 168,
    hideArrow = false,
    ...rest
}: IDropdown) {
    const controlledValue = 'value' in arguments[0];
    const controlledVisible = 'visible' in arguments[0];
    if (!Array.isArray(value) && controlledValue && multiple) {
        throw new Error('多选模式的Dropdown指定的value必须是数组');
    }
    const [isOpen, setIsOpen] = useState(false);
    const [selected, setSelected] = useState<IValue>(defaultValue || (multiple ? [] : undefined));
    if (controlledValue) {
        if (!multiple && selected !== value) {
            setSelected(value);
        } else if (multiple && (selected as any).join() != (value as any).join()) {
            setSelected(value);
        }
    }
    const hasSelected = multiple ? !!(selected as any).length : selected !== undefined;
    const ref = useRef() as any;
    const isTextContent = typeof content === 'string';
    if (controlledVisible && visible !== isOpen) {
        setIsOpen(!isOpen);
    }
    if (isTextContent) {
        content = <span>{content}</span>;
    }
    const rotate = useRotate(isOpen);

    useClickOutside(
        (e: any) => {
            if (ref.current && !ref.current.contains(e.target)) {
                if (!controlledVisible) {
                    setIsOpen(false);
                }
                onVisibleChange && isOpen && onVisibleChange(false);
            }
        },
        [isOpen]
    );

    const onClick = useCallback(() => {
        if (trigger === 'click') {
            !controlledVisible && setIsOpen(o => !o);
            controlledVisible && onVisibleChange && onVisibleChange(!isOpen);
        }
    }, [trigger, onVisibleChange, isOpen]);

    const onMouseOver = useCallback(() => {
        if (trigger === 'hover' && !isOpen) {
            setIsOpen(true);
            onVisibleChange && onVisibleChange(true);
        }
    }, [trigger, onVisibleChange, isOpen]);

    const onMouseLeave = useCallback(() => {
        if (trigger === 'hover' && isOpen) {
            setIsOpen(false);
            onVisibleChange && onVisibleChange(false);
        }
    }, [trigger, onVisibleChange, isOpen]);

    const height = Array.isArray(options) && options.length ? options.length * 36 + 12 : 'auto';
    const collapse = useTransition(isOpen, null, {
        from: { height: 0, scale: 0 },
        enter: {
            display: 'flex',
            scale: 1,
            height,
        },
        leave: { height: 0, overflow: 'hidden', scale: 0 },
        unique: false,
        config: {
            tension: 300,
            clamp: true,
        },
    });
    return (
        <Wrapper ref={ref} onClick={onClick} onMouseOver={onMouseOver} onMouseLeave={onMouseLeave} {...rest}>
            {content || children}
            {!hideArrow && (
                <Down
                    fillColor={hasSelected && indicator ? '#00a5aa' : '#868DA1'}
                    fillColorRule="&&& path:first-child"
                    style={rotate}
                />
            )}
            {collapse.map(({ item, key, props: { scale, ...rest } }) => {
                return (
                    item && (
                        <AnimatedMenu
                            style={{
                                ...rest,
                                ...{
                                    transform:
                                        scale &&
                                        scale.interpolate(
                                            (s: any) =>
                                                `scale(${s}) ${position === 'middle' ? 'translate(-50%,0)' : ''}`
                                        ),
                                    transformOrigin: position === 'end' ? 'top right' : 'top left',
                                },
                            }}
                            key={key}
                            position={position}
                        >
                            {options.length
                                ? options.map((o, index) => (
                                      <MenuItem
                                          width={width}
                                          key={index}
                                          className={isSelected(selected, o.value) ? 'item-selected' : ''}
                                          onClick={(e: any) => {
                                              // 防止触发父节点的onClick
                                              e.stopPropagation();
                                              if (multiple) {
                                                  const selected1 = [...(selected as any)];
                                                  const mIndex = selected1.indexOf(o.value);
                                                  if (~mIndex) {
                                                      selected1.splice(mIndex, 1);
                                                  } else {
                                                      selected1.push(o.value);
                                                  }
                                                  !controlledValue && setSelected(selected1);
                                                  onChange && onChange(selected1);
                                                  // multiple 不关闭弹窗
                                                  return;
                                              }
                                              let newValue;
                                              if (selected !== o.value) {
                                                  newValue = o.value;
                                              } else if (toggle) {
                                                  newValue = toggle ? undefined : o.value;
                                              } else {
                                                  newValue = selected;
                                              }
                                              !controlledValue && setSelected(newValue);

                                              onChange && onChange(newValue);
                                              !controlledVisible && setIsOpen(!isOpen);
                                              controlledVisible && onVisibleChange && onVisibleChange(false);
                                          }}
                                      >
                                          {o.label}
                                      </MenuItem>
                                  ))
                                : overlay}
                        </AnimatedMenu>
                    )
                );
            })}
        </Wrapper>
    );
};
Dropdown.defaultProps = {
    trigger: 'hover',
    options: [],
    position: 'start',
};
export default Dropdown;
