import { IEmojiIcon } from '@vev/utils';
import { isString } from 'lodash';
import React, { ReactNode, useEffect, useMemo, useRef, useState } from 'react';
import { SilkeButton } from '../silke-button';
import { BoxButtonProps, BoxLinkProps, SilkeBox } from '../silke-box';
import ButtonContext from '../silke-button/context';
import { SilkeIcon, SilkeIcons } from '../silke-icon';
import { SilkeImage } from '../silke-image';
import { SilkeText } from '../silke-text';
import styles from './silke-navigation-link.scss';
import { SilkeColor } from '../../silke-theme-provider';
import { SilkeContextMenu, SilkeContextMenuItems } from '../silke-context-menu';

type SilkeNavigationLinkProps = {
  active?: boolean;
  icon?: IEmojiIcon | SilkeIcons | React.ReactElement;
  label: ReactNode;
  subLabel?: string;
  linkClassName?: string;
  draggable?: boolean;
  color?: SilkeColor;
  items?: React.ReactElement[];
  menu?: SilkeContextMenuItems;
  /**
   * Buttons/icons shown only on hover
   */
  rightButtons?: ReactNode;
  expanded?: boolean;
} & (
  | ({ link: string } & Omit<BoxLinkProps, 'to' | 'tag' | 'link'>)
  | ({ link?: undefined } & Omit<BoxButtonProps, 'tag' | 'type'>)
);

export const SilkeNavigationLink = React.forwardRef(
  (
    {
      active,
      icon,
      label,
      subLabel,
      className,
      linkClassName,
      children,
      link,
      rightButtons,
      color,
      draggable,
      expanded,
      items,
      menu = [],
      ...rest
    }: SilkeNavigationLinkProps,
    ref: React.ForwardedRef<HTMLDivElement>,
  ) => {
    const [expand, setExpand] = useState(false);
    const [openMenu, setOpenMenu] = useState(false);
    const menuRef = useRef<HTMLButtonElement>(null);
    const cl = [styles.main];
    const linkClass = [styles.link];
    const hasItems = !!items?.length;

    if (className) cl.push(className);
    if (active) cl.push(styles.active);
    if (rightButtons) cl.push(styles.hasRightButtons);
    if (color) linkClass.push(styles[color]);
    if (linkClassName) linkClass.push(linkClassName);
    if (expanded) cl.push(styles.expanded);

    const toggleExpand = useMemo(
      () => (e: React.MouseEvent) => {
        e.stopPropagation();
        e.preventDefault();
        setExpand(!expand);
      },
      [expand],
    );

    const toggleMenu = useMemo(
      () => (e: React.MouseEvent) => {
        e.stopPropagation();
        e.preventDefault();
        setOpenMenu(!openMenu);
      },
      [openMenu],
    );

    useEffect(() => {
      if (active) setExpand(true);
    }, [active]);

    return (
      <SilkeBox
        ref={ref}
        className={cl.join(' ')}
        tag="div"
        draggable={draggable}
        onDrop={() => setExpand(true)}
      >
        <SilkeBox column fill className={styles.linkContainer}>
          <SilkeBox
            {...(typeof link === 'string'
              ? {
                  tag: 'link',
                  to: link,
                  ...(rest as Omit<BoxLinkProps, 'to' | 'tag' | 'link'>),
                }
              : {
                  tag: 'button',
                  type: 'button',
                  ...(rest as Omit<BoxButtonProps, 'tag' | 'type'>),
                })}
            className={linkClass.join(' ')}
            flex
            vAlign="center"
            gap="s"
            vPad={subLabel ? 'xxs' : undefined}
          >
            {draggable && (
              <SilkeBox className={styles.dragIcon} size="s" align="center" pad="xs">
                <SilkeIcon
                  icon="drag.dots"
                  color="neutral-60"
                  style={{ fontSize: 12, fontWeight: 400 }}
                />
              </SilkeBox>
            )}
            {icon ? (
              <SilkeBox
                size="s"
                align="center"
                pad="xs"
                className={styles.linkIcon}
                style={{ fontSize: 14, opacity: active ? 1 : 0.7 }}
              >
                {React.isValidElement(icon) || isString(icon) ? (
                  <SilkeIcon icon={icon || 'error'} />
                ) : (
                  <SilkeImage icon={icon as any} avatar="s" />
                )}
              </SilkeBox>
            ) : (
              <SilkeBox width="xs" />
            )}

            <SilkeBox column flex className={styles.label}>
              <SilkeText
                flex
                overflow
                style={{ maxWidth: children || rightButtons ? 120 : undefined, fontSize: 14 }}
              >
                {label || 'just a link'}
              </SilkeText>
              {subLabel && (
                <SilkeText size="small" color="neutral-70">
                  {subLabel}
                </SilkeText>
              )}
            </SilkeBox>
            {children || rightButtons ? (
              <ButtonContext size="s" kind="ghost">
                <SilkeBox className={styles.rightContent} vAlign="center" height="s">
                  {children}
                  {rightButtons && (
                    <div
                      className={styles.rightButtons}
                      onClick={(e: React.MouseEvent) => e.stopPropagation()}
                    >
                      {rightButtons}
                    </div>
                  )}
                </SilkeBox>
              </ButtonContext>
            ) : null}

            {(hasItems || !!menu.length) && (
              <SilkeBox gap="xxs" hPad="xs">
                {!!menu.length && (
                  <SilkeButton
                    className={openMenu ? undefined : styles.overflowMenu}
                    onMouseDown={toggleMenu}
                    onClick={(e) => {
                      e.stopPropagation();
                      e.preventDefault();
                    }}
                    ref={menuRef}
                    icon="menuMore"
                    kind="ghost"
                    size="s"
                  />
                )}
                {hasItems && (
                  <SilkeBox>
                    <SilkeButton
                      size="s"
                      kind="ghost"
                      color="neutral-60"
                      icon={expand ? 'chevron.down' : 'chevron.right'}
                      onClick={toggleExpand}
                    />
                  </SilkeBox>
                )}
              </SilkeBox>
            )}

            {openMenu && (
              <SilkeContextMenu
                anchor={menuRef}
                width={82}
                anchorOrigin="bottom-right"
                targetOrigin="top-right"
                offsetY={1}
                gap="xxs"
                items={menu}
                onRequestClose={() => setOpenMenu(false)}
              />
            )}
          </SilkeBox>

          {hasItems && expand && (
            <SilkeBox column gap="xs" pad="xs" className={styles.subLink}>
              {items?.map((item) => {
                if (React.isValidElement(item)) {
                  return item;
                }
                return false;
              })}
            </SilkeBox>
          )}
        </SilkeBox>
      </SilkeBox>
    );
  },
);

SilkeNavigationLink.displayName = 'SilkeNavigationLink';
