import { KeyboardEventCode } from '@vev/utils';
import { isString } from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
import { SilkeBox } from '../silke-box';
import { SilkeIcon, SilkeIcons } from '../silke-icon';
import { SilkeShortcuts } from './silke-shortcuts';
import { SilkeTooltip, SilkeTooltipProps } from './silke-tooltip';
import DOMPurify from 'dompurify';

type SilkeIconTooltipProps = {
  icon?: SilkeIcons;
  tooltip: React.ReactNode;
  tooltipTitle?: string;
  shortcut?: KeyboardEventCode[] | KeyboardEventCode;
  show?: boolean;
  /** If interaction content in the tooltip then this should be set to true */
  interactive?: boolean;
  noMargin?: boolean;
} & Omit<SilkeTooltipProps, 'children' | 'anchor' | 'show'>;

/**
 * Shows an icon with a tooltip anchored to it
 */
export function SilkeIconTooltip({
  icon = 'tooltip',
  interactive,
  shortcut,
  show,
  tooltip,
  tooltipTitle,
  size,
  noMargin,
  ...rest
}: SilkeIconTooltipProps) {
  const ref = useRef<HTMLElement | null>(null);
  const contentRef = useRef<HTMLElement | null>(null);
  const [hoveringIcon, setHoveringIcon] = useState(show ?? false);
  const [hoveringContent, setHoveringContent] = useState(false);

  /**
   * `shortcut`, if any, as an array
   */
  const shortcutArray = shortcut
    ? typeof shortcut === 'string'
      ? [shortcut]
      : shortcut
    : undefined;

  useEffect(() => {
    const el = ref.current;
    if (el) {
      let timeout = 0;
      const handleMouseOver = () => {
        clearTimeout(timeout);
        setHoveringIcon(true);
      };
      const handleMouseOut = () => {
        clearTimeout(timeout);
        timeout = self.setTimeout(() => setHoveringIcon(false), interactive ? 400 : 1);
      };

      el.addEventListener('mouseover', handleMouseOver, { passive: true });
      el.addEventListener('mouseleave', handleMouseOut, { passive: true });
      return () => {
        el.removeEventListener('mouseover', handleMouseOver);
        el.removeEventListener('mouseleave', handleMouseOver);
      };
    }
  }, [ref, interactive]);

  useEffect(() => {
    const contentEl = contentRef.current;
    if (interactive && contentEl) {
      const handleMouseOver = () => setHoveringContent(true);
      const handleMouseOut = () => setHoveringContent(false);

      contentEl.addEventListener('mouseover', handleMouseOver, { passive: true });
      contentEl.addEventListener('mouseleave', handleMouseOut, { passive: true });

      return () => {
        contentEl.removeEventListener('mouseover', handleMouseOver);
        contentEl.removeEventListener('mouseleave', handleMouseOut);
      };
    }
  }, [show, interactive, contentRef.current]);

  useEffect(() => {
    if (show !== undefined) setHoveringIcon(show);
  }, [show]);

  return (
    <>
      <span ref={ref} style={{ marginLeft: noMargin ? 0 : 8 }}>
        <SilkeIcon icon={icon} />
      </span>
      <SilkeTooltip
        {...rest}
        title={tooltipTitle}
        anchor={ref}
        size={size || 'tiny'}
        show={hoveringIcon || hoveringContent}
      >
        <SilkeBox gap="s" ref={contentRef} style={{ pointerEvents: interactive ? 'all' : 'none' }}>
          {isString(tooltip) ? (
            <span dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(tooltip) }} />
          ) : (
            <span>{tooltip}</span>
          )}
          <SilkeShortcuts shortcuts={shortcutArray} />
        </SilkeBox>
      </SilkeTooltip>
    </>
  );
}
