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

import * as React from "react";
import {StyleSheet, css} from "aphrodite";
import TooltipTrigger, {type TooltipArg} from "react-popper-tooltip";
import classnames from "classnames";
// TODO: Fix this eslint issue on next edit. This is an autogenerated comment.
// eslint-disable-next-line flexport/no-legacy-dependencies
import {zIndices} from "latitude/tools/deprecatedZIndices";
import StackingContext from "./StackingContext";

// prettier-ignore
export type TooltipPlacement =
  | "auto"   | "auto-start"   | "auto-end"
  | "top"    | "top-start"    | "top-end"
  | "right"  | "right-start"  | "right-end"
  | "bottom" | "bottom-start" | "bottom-end"
  | "left"   | "left-start"   | "left-end";

export type TooltipTriggerOptions =
  | "none"
  | "click"
  | "right-click"
  | "hover"
  | "focus";

type Overlay = ?React.Node | ((tooltipArgs: TooltipArg) => ?React.Node);

type Props = {|
  /** The placement of the tooltip */
  +placement?: TooltipPlacement,
  /** The trigger method */
  +trigger?: TooltipTriggerOptions,
  /** Content that shows up when the child is hovered */
  +overlay: Overlay,
  /** 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 offset of the tooltip from the trigger */
  +offset?: number,
  /** The content that triggers the tooltip on hover */
  +children: React.Node,
  /**
   * CustomTooltip wraps its tooltip content with a div for ref purpopses.
   * `tooltipClassName` can be used to style this div.
   */
  +tooltipClassName?: string,
  /**
   * 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 CustomTooltip can be used to create custom popups that occur on hover
 * @brandStatus V3
 * @status Beta
 */
export default function CustomTooltip({
  placement = "right",
  trigger = "hover",
  overlay,
  children,
  mouseEnterDelay = 0,
  mouseExitDelay = 0.15,
  offset = 0,
  tooltipClassName = "",
  triggerClassName = "",
  inline = false,
}: Props): React.Node {
  const {isDeprecatedZIndexEnabled} = React.useContext(StackingContext);
  const tooltipClasses = classnames(
    tooltipClassName,
    css(
      isDeprecatedZIndexEnabled && styles.tooltipContainerZIndex,
      overlay == null && styles.invisible
    )
  );
  return (
    <TooltipTrigger
      placement={placement}
      trigger={trigger}
      tooltip={makeTooltip(overlay, tooltipClasses)}
      delayShow={mouseEnterDelay * 1000}
      delayHide={mouseExitDelay * 1000}
      modifiers={{
        offset: {
          offset: `0,${offset}px`,
        },
      }}
    >
      {makeTrigger(children, triggerClassName, inline)}
    </TooltipTrigger>
  );
}

function makeTooltip(overlay: Overlay, tooltipClasses: ?string) {
  return tooltipArgs => (
    <div
      {...tooltipArgs.getTooltipProps({
        ref: tooltipArgs.tooltipRef,
        className: tooltipClasses,
      })}
    >
      {typeof overlay === "function" ? overlay(tooltipArgs) : overlay}
    </div>
  );
}

function makeTrigger(children: React.Node, className: string, inline: boolean) {
  const WrapperTag = inline ? "span" : "div";
  return ({getTriggerProps, triggerRef}) => (
    <WrapperTag
      {...getTriggerProps({
        ref: triggerRef,
        className: className || css(styles.trigger),
      })}
    >
      {children}
    </WrapperTag>
  );
}

const styles = StyleSheet.create({
  trigger: {
    display: "inline-block",
  },
  tooltipContainerZIndex: {
    zIndex: zIndices.zIndex1500AboveModal.zIndex,
  },
  invisible: {
    display: "none",
  },
});
