import React, { useState, useContext, useMemo, forwardRef } from "react";
import classNames from "classnames";
import { StyledProps } from "../_type";
import { Icon } from "../icon";
import { useDefault } from "../_util/use-default";
import { useConfig } from "../_util/config-context";
import { MenuContext, SubMenuContext } from "./MenuContext";
import { MenuItem } from "./MenuItem";
import { isChildOfType } from "../_util/is-child-of-type";

export interface SubMenuProps extends StyledProps {
  /**
   * 标题
   */
  title?: React.ReactNode;

  /**
   * 菜单折叠后标题处显示的图标 URL 或自定义节点内容
   *
   * **传入 `string` 类型将作为 URL 解析**
   *
   * **传递一组 URL 时，第一个 URL 会作为未激活态图标，第二个 URL 会作为激活态图标**
   *
   * @docType [React.ReactNode, React.ReactNode] | React.ReactNode
   */
  icon?: React.ReactNode | [React.ReactNode, React.ReactNode];

  /**
   * 菜单内容（Menu.Item）
   */
  children?: React.ReactNode;

  /**
   * 是否默认展开
   *
   * @default false
   */
  defaultOpened?: boolean;

  /**
   * 是否展开
   */
  opened?: boolean;

  /**
   * 展开状态变化时回调
   */
  onOpenedChange?: (opened: boolean) => void;
}

function hasSelectedItem(children: React.ReactNode) {
  let hasSelected = false;
  React.Children.forEach(children, child => {
    if (isChildOfType(child, MenuItem) && child.props.selected) {
      hasSelected = true;
    }
  });
  return hasSelected;
}

export const SubMenu = forwardRef(function SubMenu(
  props: SubMenuProps,
  ref: React.Ref<HTMLLIElement>
) {
  const defaultDefaultOpened = useMemo(
    () => hasSelectedItem(props.children),
    [] // eslint-disable-line react-hooks/exhaustive-deps
  );

  const {
    title,
    icon,
    children,
    defaultOpened = defaultDefaultOpened,
    opened: _opened,
    onOpenedChange: _onOpenedChange,
    className,
    ...restProps
  } = props;

  const { classPrefix } = useConfig();
  // 包含 tag 的子菜单项
  const [tags, setTags] = useState<string[]>([]);
  // 子菜单被选中项
  const [selectedId, setSelectedId] = useState<string>(null);

  const { collapsed } = useContext(MenuContext);

  // eslint-disable-next-line no-param-reassign
  const [opened, onOpenedChange] = useDefault(
    _opened,
    defaultOpened,
    _onOpenedChange
  );

  const [defaultIcon, activeIcon] = Array.isArray(icon) ? icon : [icon, icon];
  return (
    <li
      ref={ref}
      className={classNames(`${classPrefix}-menu__submenu`, className, {
        [`${classPrefix}-menu__subbadge`]: tags.length && !opened,
        "is-selected": !!selectedId && (collapsed || !opened),
        "is-expanded": opened,
      })}
      {...restProps}
    >
      <a
        className={`${classPrefix}-menu__item`}
        onClick={() => onOpenedChange(!opened)}
      >
        {defaultIcon &&
          (typeof defaultIcon === "string" ? (
            <img
              className={`${classPrefix}-menu__list-icon`}
              src={defaultIcon}
              alt="icon"
            />
          ) : (
            defaultIcon
          ))}
        {activeIcon &&
          (typeof activeIcon === "string" ? (
            <img
              className={`${classPrefix}-menu__list-icon is-selected`}
              src={activeIcon}
              alt="icon"
            />
          ) : (
            activeIcon
          ))}
        <div className={`${classPrefix}-menu__text`}>{title}</div>
        <Icon type="arrowdown" />
      </a>
      <ul className={`${classPrefix}-menu__list`}>
        <SubMenuContext.Provider
          value={{
            inSubMenu: true,
            onTagChange: (id, hasTag) =>
              setTags(tags => {
                if (hasTag) {
                  return [...tags, id];
                }
                return tags.filter(i => i !== id);
              }),
            onSelectedChange: (id, selected) =>
              setSelectedId(selectedId => {
                if (selected) {
                  return id;
                }
                if (id === selectedId) {
                  return null;
                }
                return selectedId;
              }),
          }}
        >
          {children}
        </SubMenuContext.Provider>
      </ul>
    </li>
  );
});

SubMenu.displayName = "SubMenu";
