import React from "react";
import { default as MuiButton } from "@mui/material/Button";
import { twJoin } from "tailwind-merge";

import { Icon } from "../icon/Icon";
import { Tooltip } from "../tooltip/Tooltip";
import { twMerge } from "../../../tailwind.config";
import { ButtonProps, MUIButtonPropWithLink } from "./types";
import { useVariant } from "./useVariant";

// Stored as array to enable choosing between square and rectangular paddings depending on the content
export const paddings = {
  tiny: { rectangular: "py-2 px-4", square: "p-2" },
  small: { rectangular: "py-4 px-10", square: "p-4" },
  default: { rectangular: "py-6 px-10", square: "p-6" },
  large: { rectangular: "p-10", square: "p-10" },
} as const;

export type StyleProps = {
  hasLabel: boolean;
  variant: NonNullable<ButtonProps["variant"]>;
  size: NonNullable<ButtonProps["size"]>;
};

const buttonBaseStyles =
  "min-w-0 ease-in-out duration-100 normal-case rounded-6 shadow-none focus-visible:ring-3 ring-B400FR hover:shadow-none";
const disabledButtonStyles = "disabled:bg-N20A disabled:text-N60";

export function useButtonStyles({ hasLabel, variant, size }: StyleProps) {
  const classes = {
    root: twJoin(
      "-outline-offset-1",
      ["default", "large"].includes(size)
        ? "text-style-M200"
        : "text-style-M100",
      hasLabel ? paddings[size].rectangular : paddings[size].square
    ),
    containedPrimary: twJoin(
      buttonBaseStyles,
      "bg-B400 text-N0 hover:bg-B500",
      disabledButtonStyles,
      "active:bg-B500 active:shadow-none active:bg-overlay from-N50A to-N50A"
    ),
    containedSecondary: "",
    outlinedSecondary: twJoin(
      buttonBaseStyles,
      "border-0 outline outline-1 outline-N40 bg-[transparent] text-N700",
      "hover:border-0 hover:bg-N20A",
      "active:bg-N30A",
      disabledButtonStyles,
      "disabled:border-0"
    ),
    startIcon: "m-0",
    endIcon: "m-0",
    textMargin: ["default", "large"].includes(size) ? "mx-2" : "m-2",
  };

  switch (variant) {
    case "secondary":
      classes.containedSecondary = twJoin(
        buttonBaseStyles,
        "bg-N20A text-N700 hover:bg-N30A active:bg-N40A",
        disabledButtonStyles
      );
      break;
    case "tertiary":
      classes.containedSecondary = twJoin(
        buttonBaseStyles,
        "bg-[transparent] text-N700 hover:bg-N20A active:bg-N30A",
        disabledButtonStyles
      );
      break;
    case "danger":
      classes.containedSecondary = twJoin(
        buttonBaseStyles,
        "bg-R400 text-N0 hover:bg-R300 active:bg-R500",
        disabledButtonStyles
      );
      break;
  }

  return classes;
}

export const Button = ({
  children,
  onClick,
  type = "button",
  disabled = false,
  variant = "primary",
  size = "default",
  to,
  fullWidth,
  icon,
  iconPosition = "start",
  iconWeight = "semibold",
  linkComponent,
  tooltip,
  tooltipProps = {},
  ESCAPE_className,
  ...restProps
}: ButtonProps) => {
  const { muiVariant, muiColor } = useVariant(variant);

  const { textMargin, ...classes } = useButtonStyles({
    variant,
    size,
    hasLabel: !!children,
  });

  const props = {
    classes: { ...classes, root: twMerge(classes.root, ESCAPE_className) },
    type,
    color: muiColor,
    variant: muiVariant,
    onClick,
    disabled,
    size: "medium",
    fullWidth,
    disableRipple: true,
    ...(to && { to, component: linkComponent }),
    ...restProps,
  } as MUIButtonPropWithLink;

  const iconComponent = icon ? (
    <Icon name={icon} weight={iconWeight} size="20" />
  ) : null;

  const iconProps = {
    [iconPosition === "end" ? "endIcon" : "startIcon"]: iconComponent,
  };

  const buttonComponent = (
    <MuiButton {...props} {...iconProps}>
      {!!children ? <span className={textMargin}>{children}</span> : null}
    </MuiButton>
  );

  if (tooltip) {
    return (
      <Tooltip tooltip={tooltip} {...tooltipProps}>
        {/* Disabled buttons don't fire events that the tooltip listens to. */}
        {disabled ? (
          <span style={{ display: "inline-flex" }}>{buttonComponent}</span>
        ) : (
          buttonComponent
        )}
      </Tooltip>
    );
  }

  return buttonComponent;
};
