import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { Children, cloneElement, forwardRef, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
import clsx from 'clsx';
import { isDef } from '../utils';
import useEventListener from '../hooks/use-event-listener';
import useScrollParent from '../hooks/use-scroll-parent';
import { getRect } from '../hooks/use-rect';
import useRefs from '../hooks/use-refs';
import DropdownMenuContext from './DropdownMenuContext';
import { useUpdateEffect } from '../hooks';
import useClickAway from '../hooks/use-click-away';
import ConfigProviderContext from '../config-provider/ConfigProviderContext';
import useMergedState from '../hooks/use-merged-state';
const DropdownMenu = forwardRef((props, ref) => {
  const {
    prefixCls,
    createNamespace
  } = useContext(ConfigProviderContext);
  const [bem] = createNamespace('dropdown-menu', prefixCls);
  const [innerValue = {}, setInnerValue] = useMergedState({
    value: props.value,
    defaultValue: props.defaultValue
  });
  const [childrenRefs, setChildrenRefs] = useRefs();
  const [showPopupIndex, setShowPopupIndex] = useState(null);
  const showPopupIndexRef = useRef();
  const root = useRef();
  const barRef = useRef();
  const offset = useRef(0);
  const isToggleEvent = useRef(false);
  const rect = useRef({
    bottom: 0,
    top: 0
  });
  const innerEffect = useRef(false);
  const opened = useMemo(() => showPopupIndex !== null, [showPopupIndex]);

  const barStyle = () => {
    if (opened && isDef(props.zIndex)) {
      return {
        zIndex: +props.zIndex + 1
      };
    }

    return {};
  };

  const updateShowPopupIndex = current => {
    showPopupIndexRef.current = current;
    setShowPopupIndex(current);
  };

  const closeAll = () => {
    childrenRefs.forEach(item => {
      item.toggle(false);
    });
    updateShowPopupIndex(null);
  };

  const onClickAway = () => {
    if (props.closeOnClickOutside && !isToggleEvent.current) {
      closeAll();
    } else {
      isToggleEvent.current = false;
    }
  };

  const updateOffset = () => {
    if (barRef.current) {
      rect.current = getRect(barRef.current);

      if (props.direction === 'down') {
        offset.current = rect.current.bottom;
      } else {
        offset.current = window.innerHeight - rect.current.top;
      }
    }
  };

  const onScroll = () => {
    if (opened) {
      updateOffset();
    }
  };

  const showItem = index => {
    const item = childrenRefs[index];
    isToggleEvent.current = true;
    updateOffset();
    updateShowPopupIndex(index);
    item.toggle(true);
  };

  const toggleItem = active => {
    childrenRefs.forEach((item, index) => {
      if (index === active) {
        if (active === showPopupIndexRef.current) {
          updateShowPopupIndex(null);
          item.toggle();
          return;
        }

        showItem(active);
      }
    });
  };

  const close = () => {
    updateShowPopupIndex(null);
  };

  const renderTitle = (item, index) => {
    const showPopup = showPopupIndex === index;
    const {
      titleClass
    } = item;
    const disabled = props.disabled || item.disabled;
    return _jsx("div", Object.assign({
      role: "button",
      tabIndex: disabled ? -1 : 0,
      className: clsx(bem('item', {
        disabled
      })),
      onClick: () => {
        if (!disabled) {
          toggleItem(index);
        }
      }
    }, {
      children: _jsx("span", Object.assign({
        className: clsx(bem('title', {
          down: showPopup === (props.direction === 'down'),
          active: showPopup
        }), titleClass),
        style: {
          color: showPopup ? props.activeColor : ''
        }
      }, {
        children: _jsx("div", Object.assign({
          className: "rv-ellipsis"
        }, {
          children: item.renderTitle(innerValue[item.name])
        }))
      }))
    }), index);
  };

  useUpdateEffect(() => {
    if (innerEffect.current) {
      innerEffect.current = false;
      return;
    }

    if (!props.value) {
      setInnerValue(undefined);
      return;
    }

    setInnerValue(props.value);
  }, [props.value]);
  useEffect(() => {
    if (barRef.current) {
      updateOffset();
    }
  }, [barRef.current]);

  const onInnerChange = v => {
    innerEffect.current = true;
    const newValue = Object.assign(Object.assign({}, innerValue), v);
    setInnerValue(newValue);
    if (props.onChange) props.onChange(newValue);
  };

  const scrollParent = useScrollParent(root);
  useEventListener('scroll', onScroll, {
    target: scrollParent
  });
  useClickAway(root, onClickAway);
  useImperativeHandle(ref, () => ({
    toggleItem,
    showItem,
    close: closeAll
  }));
  return _jsx(DropdownMenuContext.Provider, Object.assign({
    value: {
      props,
      value: innerValue,
      onChange: onInnerChange,
      close
    }
  }, {
    children: _jsxs("div", Object.assign({
      ref: root,
      className: clsx(bem(), props.className),
      style: Object.assign({}, props.style)
    }, {
      children: [_jsx("div", Object.assign({
        ref: barRef,
        style: barStyle(),
        className: clsx(bem('bar', {
          opened
        }))
      }, {
        children: childrenRefs.map(renderTitle)
      })), Children.toArray(props.children).filter(Boolean).map((child, index) => cloneElement(child, {
        ref: setChildrenRefs(index),
        offset: offset.current,
        showPopup: showPopupIndex === index
      }))]
    }))
  }));
});
DropdownMenu.defaultProps = {
  duration: 200,
  overlay: true,
  closeOnClickOutside: true,
  closeOnClickOverlay: true,
  direction: 'down',
  defaultValue: {}
};
export default DropdownMenu;