"use client";
import { jsx, jsxs } from "../../packages/jsx/src/jsx-runtime.js";
import { forwardRef, useContext, Fragment } from "react";
import { ButtonGroupContext, DEFAULT_SIZE } from "./common.js";
import { getChildrenChunks } from "../../utils/getChildrenChunks.js";
import { buildTransition, buildShadow, buildBorder } from "../../tokens/utils.js";
import { mapResponsiveStyleValue } from "../../theme/utils.js";
import { Flex } from "../../atoms/Flex/Flex.js";
import { Text } from "../../atoms/Text/Text.js";
import { Spacing } from "../../tokens/Spacing.js";
import { Icon } from "../../atoms/Icon/Icon.js";
import { BorderRadius } from "../../tokens/BorderRadius.js";
import { ButtonOrLink } from "../../atoms/ButtonOrLink/ButtonOrLink.js";
import { classNames } from "../../utils/classNames.js";
const baseStyles = {
  color: "White88",
  '&:is(:disabled, [aria-disabled="true"])': {
    color: "White32"
  }
};
const baseInteractiveStyles = {
  "&:where(:focus-visible)": {
    color: "White",
    textShadow: buildShadow("S"),
    // Remove the default focus ring but add custom focus styles if the button is not in a group (because when it is, the focus styles are on the whole group)
    outline: "none",
    "&:where(:not(.gds-ButtonGroup *))": {
      borderColor: "Purple",
      outline: buildBorder("Purple16", "8px"),
      outlineOffset: 0
    }
  },
  "&:where(:hover)": {
    color: "White",
    textShadow: buildShadow("S")
  },
  "&:where(:active)": {
    color: "White64",
    textShadow: "none",
    // Clicking on a button should show the active styles instantly (otherwise they wouldn't be visible when clicking and releasing instantly)
    // Note that there is still a "release" transition, since the button is no longer `:active`
    transition: "none"
  },
  // Dim button when another button from the same group is hovered, unless specifically focused
  "*:where(.gds-ButtonGroup:hover) &:where(:not(:hover, :focus-visible))": {
    color: "White32"
  },
  // Dim button when another button from the same group is focused, unless specifically hovered
  "*:where(.gds-ButtonGroup:has(:focus-visible)) &:where(:not(:focus-visible, :hover))": {
    color: "White32"
  }
};
const getStatusOrVariantStyles = (status, variant) => {
  switch (status) {
    case "success":
    case "loading":
      return {
        bg: "Midnight64",
        borderColor: "White4",
        color: "White"
      };
    case "success-final":
      return {
        bg: "Green16",
        borderColor: "Green4",
        color: "White"
      };
    case "error":
      return {
        bg: "Red4",
        borderColor: "Red4",
        color: "Red"
      };
    case "loading-progress":
      return {
        bg: "Purple4",
        borderColor: "Purple8",
        color: "White"
      };
    case null:
      break;
    default: {
      return {};
    }
  }
  const getStyles = (variantStyles, variantInteractiveStyles) => {
    return {
      ...baseStyles,
      // Using `&` to prevent selectors in `baseStyles` from being overwritten by the same selectors in `variantStyles`
      "&": {
        ...variantStyles
      },
      '&:not(:disabled, [aria-disabled="true"])': {
        ...baseInteractiveStyles,
        "&": {
          ...variantInteractiveStyles
        }
      }
    };
  };
  switch (variant) {
    case "primary":
      return getStyles(
        {
          bg: "Purple64",
          '&[aria-selected="true"], &[aria-pressed="true"]': {
            bg: "Purple88"
          },
          '&:is(:disabled, [aria-disabled="true"])': {
            bg: "Purple32"
          }
        },
        {
          // If hovered or inside a group where a button is hovered
          "&:where(:hover), *:where(.gds-ButtonGroup:hover) &": {
            bg: "Purple88"
          },
          // If focused or inside a group where a button is focused
          "&:where(:focus-visible), *:where(.gds-ButtonGroup:has(:focus-visible)) &": {
            bg: "Purple88"
          },
          // If pressed or inside a group where a button is pressed
          "&:where(:active), *:where(.gds-ButtonGroup:active) &": {
            bg: "Purple48"
          }
        }
      );
    case "danger":
      return getStyles(
        {
          bg: "Red88",
          '&[aria-selected="true"], &[aria-pressed="true"]': {
            bg: "Red"
          },
          '&:is(:disabled, [aria-disabled="true"])': {
            bg: "Red32"
          }
        },
        {
          "&:where(:hover), *:where(.gds-ButtonGroup:hover) &": {
            bg: "Red"
          },
          "&:where(:focus-visible), *:where(.gds-ButtonGroup:has(:focus-visible)) &": {
            bg: "Red"
          },
          "&:where(:active), *:where(.gds-ButtonGroup:active) &": {
            bg: "Red64"
          },
          "&:where(:focus-visible):where(:not(.gds-ButtonGroup *))": {
            borderColor: "Red",
            outline: buildBorder("Red16", "8px"),
            outlineOffset: 0
          }
        }
      );
    case "secondary":
      return getStyles(
        {
          bg: "White8",
          '&[aria-selected="true"], &[aria-pressed="true"]': {
            bg: "White16"
          }
        },
        {
          "&:where(:hover), *:where(.gds-ButtonGroup:hover) &": {
            bg: "White16"
          },
          "&:where(:focus-visible), *:where(.gds-ButtonGroup:has(:focus-visible)) &": {
            bg: "White8"
          },
          "&:where(:active), *:where(.gds-ButtonGroup:active) &": {
            bg: "White8"
          }
        }
      );
    case "tertiary":
      return getStyles(
        {
          bg: "transparent",
          '&[aria-selected="true"], &[aria-pressed="true"]': {
            bg: "White4"
          }
        },
        {
          "&:where(:hover), *:where(.gds-ButtonGroup:hover) &": {
            bg: "White4"
          },
          "&:where(:focus-visible), *:where(.gds-ButtonGroup:has(:focus-visible)) &": {
            bg: "White4"
          },
          "&:where(:active), *:where(.gds-ButtonGroup:active) &": {
            bg: "transparent"
          }
        }
      );
    default: {
      return {};
    }
  }
};
const ButtonBase = forwardRef(
  ({
    variant: variantProp,
    size: sizeProp,
    shape = "default",
    justify = "center",
    status = null,
    statusMessage = null,
    loadingProgress = 0,
    href,
    disabled: disabledProp = false,
    selected,
    className,
    children,
    ...rest
  }, ref) => {
    const childrenChunks = getChildrenChunks(children);
    const isIconOnly = childrenChunks.length === 1 && childrenChunks[0].isIcon;
    const buttonGroupContext = useContext(ButtonGroupContext);
    const variant = variantProp ?? buttonGroupContext.variant;
    const size = sizeProp ?? buttonGroupContext.size;
    const iconSize = mapResponsiveStyleValue(size, DEFAULT_SIZE, (value) => value === "medium" ? "16px" : "14px");
    const textSize = mapResponsiveStyleValue(size, DEFAULT_SIZE, (value) => value === "medium" ? "14px" : "12px");
    const hasStatus = status !== null;
    const disabled = buttonGroupContext.disabled ?? disabledProp;
    const Element = hasStatus ? "div" : ButtonOrLink;
    return /* @__PURE__ */ jsx(
      "div",
      {
        className: classNames(["gds-Button", className]),
        sx: {
          // Prevent icon-only buttons from shrinking (looking bad) when placed in a group that also contains a button with truncated text (text that overflows)
          flexShrink: isIconOnly ? 0 : void 0,
          // Setting the height here so it can be overridden with the `sx` prop
          height: mapResponsiveStyleValue(size, DEFAULT_SIZE, (value) => value === "medium" ? "48px" : "32px")
        },
        children: /* @__PURE__ */ jsxs(
          Element,
          {
            ref,
            sx: {
              // Using CSS Grid to ensure that a button with a `status` is at least as wide as it would be without the status
              // That is achieved by rendering the status icon/message in the same grid cell as the button's label, which is hidden with `visibility: hidden`, retaining its space in the layout
              display: "grid",
              alignItems: "center",
              width: "100%",
              height: "100%",
              px: mapResponsiveStyleValue(
                size,
                DEFAULT_SIZE,
                (value) => value === "medium" ? isIconOnly ? Spacing["16px"] : Spacing["24px"] : isIconOnly ? "9px" : Spacing["12px"]
              ),
              // Add a 1px transparent border so the layout doesn't change when the border color changes (e.g. on focus)
              border: "transparent",
              borderRadius: shape === "round" ? BorderRadius.FULL : BorderRadius.S,
              // No left border radius on buttons inside a group, except for the first
              "*:where(.gds-ButtonGroup .gds-Button:not(:first-of-type)) &": {
                borderStartStartRadius: 0,
                borderEndStartRadius: 0,
                // Also apply a divider between the button on the left and this one
                borderInlineStart: "White16"
              },
              // No right border radius on buttons inside a group, except for the last
              "*:where(.gds-ButtonGroup .gds-Button:not(:last-of-type)) &": {
                borderStartEndRadius: 0,
                borderEndEndRadius: 0
              },
              // Prevent clicking the button or changing the cursor on hover if it's disabled or if there is a status
              // Note that preventing focus is already handled by `buttonOrLink` (by setting the `disabled` attribute if the element is a `button`, and by not passing `href` if the element is a `a`)
              pointerEvents: disabled || hasStatus ? "none" : void 0,
              transition: buildTransition("ALL", "400ms"),
              ...getStatusOrVariantStyles(status, variant)
            },
            ...rest,
            href,
            disabled,
            selected,
            children: [
              status === "loading-progress" ? /* @__PURE__ */ jsx(
                "div",
                {
                  sx: {
                    position: "absolute",
                    inset: 0,
                    m: "-1px",
                    // Offset the parent's border
                    borderRadius: "inherit",
                    overflow: "hidden",
                    willChange: "transform"
                  },
                  children: /* @__PURE__ */ jsx(
                    "div",
                    {
                      sx: {
                        position: "absolute",
                        inset: 0,
                        bg: "Purple16",
                        transform: `scaleX(${loadingProgress})`,
                        transformOrigin: "left",
                        transition: buildTransition("TRANSFORM")
                      }
                    }
                  )
                }
              ) : null,
              /* @__PURE__ */ jsx(
                Flex.Row,
                {
                  as: "span",
                  justify,
                  align: "center",
                  gap: mapResponsiveStyleValue(
                    size,
                    DEFAULT_SIZE,
                    (value) => value === "medium" ? Spacing["8px"] : Spacing["4px"]
                  ),
                  sx: {
                    gridArea: "1 / 1",
                    m: "-1px",
                    // Offset the parent's border
                    visibility: hasStatus ? "hidden" : void 0,
                    "--gds-Icon-size-default": iconSize
                  },
                  children: childrenChunks.map((childrenChunk, childrenChunkIndex) => {
                    if (childrenChunk.isIcon) {
                      return /* @__PURE__ */ jsx(Fragment, { children: childrenChunk.children[0] }, childrenChunkIndex);
                    } else {
                      return /* @__PURE__ */ jsx(
                        Text.H,
                        {
                          size: textSize,
                          as: "span",
                          color: "inherit",
                          truncate: true,
                          sx: {
                            // Add some extra padding to ensure that the text shadow is not clipped by the `truncate`, then offset it with negative margin
                            p: Spacing["32px"],
                            m: `-${Spacing["32px"]}`,
                            // Prevent the clickable area from extending past the button
                            pointerEvents: "none"
                          },
                          children: childrenChunk.children
                        },
                        childrenChunkIndex
                      );
                    }
                  })
                }
              ),
              hasStatus ? /* @__PURE__ */ jsxs(
                Flex.Row,
                {
                  as: "span",
                  justify: "center",
                  align: "center",
                  gap: mapResponsiveStyleValue(
                    size,
                    DEFAULT_SIZE,
                    (value) => value === "medium" ? Spacing["8px"] : Spacing["4px"]
                  ),
                  role: "status",
                  sx: {
                    gridArea: "1 / 1",
                    m: "-1px"
                    // Offset the parent's border
                  },
                  children: [
                    statusMessage ? /* @__PURE__ */ jsx(Text.H, { as: "span", size: textSize, color: "inherit", weight: "REGULAR", truncate: true, children: statusMessage }) : null,
                    (() => {
                      switch (status) {
                        case "success":
                        case "success-final":
                          return /* @__PURE__ */ jsx(Icon.Check, { size: iconSize, color: "Green", title: "Success" });
                        case "error":
                          return /* @__PURE__ */ jsx(Icon.Close, { size: iconSize, color: "Red", title: "Error" });
                        case "loading":
                        case "loading-progress":
                          return /* @__PURE__ */ jsx(Icon.Loading, { size: iconSize, title: "Loading" });
                        default:
                          return null;
                      }
                    })()
                  ]
                }
              ) : null
            ]
          }
        )
      }
    );
  }
);
ButtonBase.displayName = "Button";
const ButtonPrimary = forwardRef((props, ref) => /* @__PURE__ */ jsx(ButtonBase, { ref, ...props, variant: "primary" }));
ButtonPrimary.displayName = "Button.Primary";
const ButtonSecondary = forwardRef((props, ref) => /* @__PURE__ */ jsx(ButtonBase, { ref, ...props, variant: "secondary" }));
ButtonSecondary.displayName = "Button.Secondary";
const ButtonTertiary = forwardRef((props, ref) => /* @__PURE__ */ jsx(ButtonBase, { ref, ...props, variant: "tertiary" }));
ButtonTertiary.displayName = "Button.Tertiary";
export {
  ButtonBase,
  ButtonPrimary,
  ButtonSecondary,
  ButtonTertiary
};
