/**
 * TEAM: frontend_infra
 * @flow strict
 */

import * as React from "react";
import {StyleSheet, css} from "aphrodite";
import CustomTooltip, {
  type TooltipPlacement,
  type TooltipTriggerOptions,
} from "./CustomTooltip";

import colors from "./colors";

export type {TooltipPlacement};

const tooltipOffset = 8;

type Props = {|
  /** The placement of the tooltip */
  +placement?: TooltipPlacement,
  /** Tooltip trigger method - defaults to 'hover'. Please do not use 'click' value for accessibility reasons. (see go/pull/136841 and https://www.w3.org/TR/wai-aria-practices/#tooltip) */
  +trigger?: TooltipTriggerOptions,
  /** Content that shows up when the child is hovered */
  +overlay: ?React.Node,
  /** Seconds the user has to hover before the tooltip shows up */
  +mouseEnterDelay?: number,
  /** Seconds until the tooltip hides after the user unhovers the tooltip */
  +mouseExitDelay?: number,
  /** The maximum width of the tooltip */
  +maxWidth?: number,
  /** The content that triggers the tooltip on hover */
  +children: React.Node,
  /**
   * CustomTooltip wraps its content with a div for ref purpopses.
   * `triggerClassName` can be used to style this div.
   */
  +triggerClassName?: string,
  /**
   * Indicate if the children should be placed in an inline element. By default we will use
   * div to wrap the children. If inline is set to true, we will use span to wrap the children.
   */
  +inline?: boolean,
|};

/**
 * @category Overlay
 * @short Tooltip can be used to create textful content that popups up on hover
 * @brandStatus V3
 * @status Beta
 */
export default function Tooltip({
  placement = "right",
  trigger = "hover",
  overlay,
  children,
  mouseEnterDelay = 0,
  mouseExitDelay = 0.15,
  maxWidth,
  triggerClassName = "",
  inline = false,
}: Props): React.Node {
  const computedStyles = React.useMemo(
    () => computeStyles(maxWidth),
    [maxWidth]
  );

  const tooltip = ({arrowRef, getArrowProps}) => (
    <>
      <div
        {...getArrowProps({
          ref: arrowRef,
          className: css(styles.tooltipArrow, getPlacementStyles(placement)),
        })}
      />
      <div className={css(styles.tooltipContent)}>{overlay}</div>
    </>
  );

  return overlay == null ? (
    children
  ) : (
    <CustomTooltip
      placement={placement}
      trigger={trigger}
      overlay={tooltip}
      mouseEnterDelay={mouseEnterDelay}
      mouseExitDelay={mouseExitDelay}
      offset={tooltipOffset}
      tooltipClassName={css(computedStyles.tooltip)}
      triggerClassName={triggerClassName}
      inline={inline}
    >
      {children}
    </CustomTooltip>
  );
}

function getPlacementStyles(placement: string) {
  switch (placement) {
    case "top":
    case "top-start":
    case "top-end":
      return styles.downArrow;
    case "bottom":
    case "bottom-start":
    case "bottom-end":
      return styles.upArrow;
    case "left":
    case "left-start":
    case "left-end":
      return styles.rightArrow;
    case "right":
    case "right-start":
    case "right-end":
      return styles.leftArrow;
    default:
      return null;
  }
}

function computeStyles(maxWidth?: number) {
  const tooltipStyle = maxWidth !== null ? {maxWidth} : {};

  return StyleSheet.create({
    tooltip: tooltipStyle,
  });
}

const arrowVerticalOffset = "-14px";

const styles = StyleSheet.create({
  tooltipContent: {
    backgroundColor: colors.grey60,
    boxShadow: "0 0 4px rgba(0, 0, 0, 0.17)",
    color: colors.white,
    padding: "12px",
    textAlign: "left",
    textDecoration: "none",
    wordBreak: "break-word",
  },
  tooltipArrow: {
    position: "absolute",
    width: 0,
    height: 0,
    borderColor: "transparent",
    borderStyle: "solid",
    borderWidth: "8px",
  },
  upArrow: {
    top: arrowVerticalOffset,
    borderBottomColor: colors.grey60,
  },
  downArrow: {
    bottom: arrowVerticalOffset,
    borderTopColor: colors.grey60,
  },
  leftArrow: {
    left: arrowVerticalOffset,
    borderRightColor: colors.grey60,
  },
  rightArrow: {
    right: arrowVerticalOffset,
    borderLeftColor: colors.grey60,
  },
});
