import { ReactNode } from "react";
import { useTranslation } from "react-i18next";
import { Button, IconButton, Tooltip } from "@mui/joy";
import { generateDialog } from "../Dialog";
import Icon from "../Icon";

const openUrl = (url?: string) => {
  window.open(url, "_blank");
};

/** Options for {@link HelpButton} */
interface HelpProps {
  /**
   * Plain text to show in the dialog.
   *
   * If the text contains "\n", it will be split to multiple paragraphs.
   */
  text?: string;
  /**
   * The title of the dialog.
   *
   * If not provided, the title will be set according to the `icon` prop.
   */
  title?: string;
  /**
   * External documentation URL.
   *
   * If provided, this will be shown as a link button in the bottom of the dialog.
   *
   * If provided alone, the button will just open the URL in a new tab.
   *
   * @param {string} url - External URL to the documentation.
   */
  url?: string;
  /**
   * The tooltip of the button.
   */
  hint?: string | "none";
  /**
   * The placement of the hovering hint.
   * @defaultValue "top"
   */
  hintPlacement?: "top" | "bottom" | "left" | "right";
  /**
   * The icon to show in the button.
   *
   * Also used to infer `title` and `hint`, if they are not provided.
   *
   * @defaultValue Icon.HelpCircle
   * @see {@link Icon.LucideIcon}
   */
  icon?: Icon.LucideIcon | "link" | "info" | "help" | "alert" | "warn";
  /**
   * The className for the button.
   * @defaultValue `!-mt-2` (aligns the button vertically with nearby text)
   */
  className?: string;
  /**
   * The color of the button.
   * @defaultValue "neutral"
   */
  color?: "primary" | "neutral" | "danger" | "info" | "success" | "warning";
  /**
   * The variant of the button.
   * @defaultValue "plain"
   */
  variant?: "plain" | "outlined" | "soft" | "solid";
  /**
   * The size of the button.
   * @defaultValue "md"
   */
  size?: "sm" | "md" | "lg";
  /**
   * `ReactNode` HTML content to show in the dialog.
   *
   * If provided, will be shown before `text`.
   *
   * You'll probably want to use `text` instead.
   */
  children?: ReactNode | undefined;
}

interface HelpDialogProps extends HelpProps, DialogProps {}

const HelpfulDialog: React.FC<HelpDialogProps> = (props: HelpDialogProps) => {
  const { t } = useTranslation();
  const { children, destroy, icon } = props;
  const LucideIcon = icon as Icon.LucideIcon;
  const handleCloseBtnClick = () => {
    destroy();
  };

  return (
    <>
      <div className="dialog-header-container">
        <LucideIcon size="24" />
        <p className="title-text text-left">{props.title}</p>
        <button className="btn close-btn" onClick={handleCloseBtnClick}>
          <Icon.X />
        </button>
      </div>
      <div className="dialog-content-container max-w-sm">
        {children}
        {props.text
          ? props.text.split(/\n|\\n/).map((text) => {
              return (
                <p key={text} className="mt-2 break-words text-justify">
                  {text}
                </p>
              );
            })
          : null}
        <div className="mt-2 w-full flex flex-row justify-end space-x-2">
          {props.url ? (
            <Button className="btn-normal" variant="outlined" color={props.color} onClick={() => openUrl(props.url)}>
              {t("common.learn-more")}
              <Icon.ExternalLink className="ml-1 w-4 h-4 opacity-80" />
            </Button>
          ) : null}
          <Button className="btn-normal" variant="outlined" color={props.color} onClick={handleCloseBtnClick}>
            {t("common.close")}
          </Button>
        </div>
      </div>
    </>
  );
};

function showHelpDialog(props: HelpProps) {
  generateDialog(
    {
      className: "help-dialog",
      dialogName: "help-dialog",
      clickSpaceDestroy: true,
    },
    HelpfulDialog,
    props
  );
}

/**
 * Show a helpful `IconButton` that behaves differently depending on the props.
 *
 * The main purpose of this component is to avoid UI clutter.
 * 
 * Use the property `icon` to set the icon and infer the title and hint automatically.
 *
 * Use cases:
 *  - Button with just a hover hint
 *  - Button with a hover hint and link
 *  - Button with a hover hint that opens a dialog with text and a link.
 *
 * @example
 * <Helpful hint="Hint" />
 * <Helpful hint="This is a hint with a link" url="https://usememos.com/" />
 * <Helpful icon="warn" text={t("i18n.key.long-dialog-text")} url="https://usememos.com/" />
 * <Helpful />
 * 
 * <div className="flex flex-row">  
 *  <span className="ml-2">Sample alignment</span>
 *  <Helpful hint="Button with hint" />
 * </div>

 * @param props.title - The title of the dialog. Defaults to "Learn more" i18n key.
 * @param props.text - Plain text to show in the dialog. Line breaks are supported.
 * @param props.url - External memos documentation URL.
 * @param props.hint - The hint when hovering the button.
 * @param props.hintPlacement - The placement of the hovering hint. Defaults to "top".
 * @param props.icon - The icon to show in the button.
 * @param props.className - The class name for the button.
 * @param {HelpProps} props - See {@link HelpDialogProps} for all exposed props.
 */
const HelpButton = (props: HelpProps): JSX.Element => {
  const { t } = useTranslation();
  const color = props.color ?? "neutral";
  const variant = props.variant ?? "plain";
  const className = props.className ?? "";
  const hintPlacement = props.hintPlacement ?? "top";
  const iconButtonSize = "sm";

  const dialogAvailable = props.text || props.children;
  const clickActionAvailable = props.url || dialogAvailable;
  const onlyUrlAvailable = props.url && !dialogAvailable;

  let LucideIcon = (() => {
    switch (props.icon) {
      case "info":
        return Icon.Info;
      case "help":
        return Icon.HelpCircle;
      case "warn":
      case "alert":
        return Icon.AlertTriangle;
      case "link":
        return Icon.ExternalLink;
      default:
        return Icon.HelpCircle;
    }
  })() as Icon.LucideIcon;

  const hint = (() => {
    switch (props.hint) {
      case undefined:
        return t(
          (() => {
            if (!dialogAvailable) {
              LucideIcon = Icon.ExternalLink;
            }
            switch (LucideIcon) {
              case Icon.Info:
                return "common.dialog.info";
              case Icon.AlertTriangle:
                return "common.dialog.warning";
              case Icon.ExternalLink:
                return "common.learn-more";
              case Icon.HelpCircle:
              default:
                return "common.dialog.help";
            }
          })()
        );
      case "":
      case "none":
      case "false":
      case "disabled":
        return undefined;
      default:
        return props.hint;
    }
  })();

  const sizePx = (() => {
    switch (props.size) {
      case "sm":
        return 14;
      case "lg":
        return 18;
      case "md":
      default:
        return 16;
    }
  })();

  if (!dialogAvailable && !clickActionAvailable && !props.hint) {
    return (
      <IconButton className={className} color={color} variant={variant} size={iconButtonSize}>
        <LucideIcon size={sizePx} />
      </IconButton>
    );
  }

  const wrapInTooltip = (element: JSX.Element) => {
    if (!hint) {
      return element;
    }
    return (
      <Tooltip placement={hintPlacement} title={hint} color={color} variant={variant} size={props.size}>
        {element}
      </Tooltip>
    );
  };

  if (clickActionAvailable) {
    props = { ...props, title: props.title ?? hint, hint: hint, color: color, variant: variant, icon: LucideIcon };
    const clickAction = () => {
      dialogAvailable ? showHelpDialog(props) : openUrl(props.url);
    };
    LucideIcon = dialogAvailable || onlyUrlAvailable ? LucideIcon : Icon.ExternalLink;
    return wrapInTooltip(
      <IconButton className={className} color={color} variant={variant} size={iconButtonSize} onClick={clickAction}>
        <LucideIcon size={sizePx} />
      </IconButton>
    );
  }

  return wrapInTooltip(
    <IconButton className={className} color={color} variant={variant} size={iconButtonSize}>
      <LucideIcon size={sizePx} />
    </IconButton>
  );
};

export default HelpButton;
