import { forwardRef } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import useResponsiveValues from "../../../hooks/breakpoint/useResponsiveValues/index.js";
import CustomPropTypes from "../../../utils/prop-types/index.js";
import normalizeStatefulColorSet from "../../../utils/colors/normalizeStatefulColorSet.js";
import getColor from "../../../utils/colors/getColor.js";
import { merge } from "../../../utils/css/cx.js";
import getPaddingClasses from "../../../utils/css/getPaddingClasses.js";
import getEdgeClasses from "../../../utils/css/getEdgeClasses.js";
import getShadowClasses from "../../../utils/css/getShadowClasses.js";
import customizable from "../../../utils/css/customizable.js";
import classes from './styles.module.scss';
const customCx = merge(classes, {
  customizable: ['Button', 'Button__icon']
});

/**
 * Renders an interactive button that can either trigger some action or
 * navigate the user to a new location. The text within a button should clearly
 * describe what it will do, and if a button is disabled its title text should
 * help communicate both why it's disabled and what the user needs to do to
 * enable it. As with all UI elements, if you are customizing the colors of
 * a button you should verify that the text on your button meets our contrast
 * standards.
 *
 * Note that the button's behavior depends on whether or not you provide
 * a value for the `href` prop. If you speficy an `href`, the button becomes
 * a link, and is rendered as an `<a>` tag rather than as a `<button>`. To
 * ensure that your application is accessible, you should _always_ use the
 * `href` prop when the button performs navigation; _do not_ use the `onClick`
 * handler to navigate the user to a new location. You can use `onClick` _with_
 * `href` though if you need to perform any side-effects along with the
 * navigation, like recording analytics.
 *
 * Any additional props beyond those listed below are forwarded to the
 * underlying tag. This is most useful when rendering links with the `href`
 * prop because you can include things like `_target="parent"` or similar as
 * necessary.
 *
 * ```js
 *
 * import { Button } from '@politico/interactive-style';
 * ```
 */
const Button = forwardRef((props, ref) => {
  const {
    size,
    label,
    active,
    disabled,
    edge,
    icon,
    href,
    onClick,
    filled,
    bg,
    fg,
    border,
    shadow,
    title,
    padding,
    ...restProps
  } = props;
  const states = ['default', 'active', 'hover', 'disabled'];
  const bgs = normalizeStatefulColorSet(bg, states);
  const fgs = normalizeStatefulColorSet(fg, states);
  const borders = normalizeStatefulColorSet(border, states);
  const paddingValue = useResponsiveValues(padding);
  const pads = getPaddingClasses(paddingValue);
  const edgeClasses = getEdgeClasses(edge);
  const shadowClasses = getShadowClasses(shadow);
  const Tag = href ? 'a' : 'button';
  return <Tag ref={ref} {...restProps} type={href ? undefined : 'button'} className={customCx(customizable('Button'), 'button', size, edgeClasses, shadowClasses, pads, {
    hollow: !filled,
    active: !disabled && active,
    defaultPadding: !padding
  })} style={{
    '--Button-bg': getColor(bgs.default),
    '--Button-fg': getColor(fgs.default),
    '--Button-border': getColor(borders.default),
    '--Button-active-bg': getColor(bgs.active),
    '--Button-active-fg': getColor(fgs.active),
    '--Button-active-border': getColor(borders.active),
    '--Button-hover-bg': getColor(bgs.hover),
    '--Button-hover-fg': getColor(fgs.hover),
    '--Button-hover-border': getColor(borders.hover),
    '--Button-disabled-bg': getColor(bgs.disabled),
    '--Button-disabled-fg': getColor(fgs.disabled),
    '--Button-disabled-border': getColor(borders.disabled)
  }} disabled={disabled} title={title} href={href && disabled ? '#' : href} onClick={disabled ? undefined : onClick}>
      <span className={classes.content}>
        {!!icon && <span className={classnames(customizable('Button__icon'), classes.icon)}>
            {icon}
          </span>}
        {label}
      </span>
    </Tag>;
});
Button.displayName = 'Button';
Button.defaultProps = {
  size: 'md',
  active: false,
  disabled: false,
  edge: '8',
  icon: undefined,
  href: undefined,
  onClick: undefined,
  filled: true,
  bg: undefined,
  fg: undefined,
  border: undefined,
  shadow: undefined,
  title: undefined,
  padding: undefined
};
Button.propTypes = {
  /**
   * The text that is rendered within the button. This should serve as a label
   * that sufficiently describes what the button will do when activated.
   */
  label: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]).isRequired,
  /**
   * The size of the button. This determines the text size and padding of the
   * button.
   */
  size: PropTypes.oneOf(['sm', 'md', 'lg']),
  /**
   * Mark the button as disabled. This will change the button's coloration and
   * remove the click listener from the button entirely. It will also replace
   * the `href` with `#` if there is an `href`.
   */
  disabled: PropTypes.bool,
  /**
   * Mark the button as active. This will change the button's coloration. Note
   * that a button cannot be considered active if it is disabled.
   */
  active: PropTypes.bool,
  /**
   * Set the corner style of the button to one of our standard edge levels. In
   * general, either sharp or round buttons should be used consistently within
   * a single project.
   */
  edge: PropTypes.oneOf(['0', '1', '2', '3', '4', '5', '6', '8', 'round', 'sharp', 'max']),
  /**
   * An icon component to display within the button (if any).
   */
  icon: PropTypes.node,
  /**
   * A URL that this button should link to. If you provide an `href` prop then
   * the Button will be rendered as an `<a>` tag rather than as a `<button>`
   * tag.
   */
  href: PropTypes.string,
  /**
   * A click handler that will be called when a user activates the button. The
   * callback is attached directly, so it will be invoked with the triggering
   * event.
   */
  onClick: PropTypes.func,
  /**
   * Set whether the button is filled with a color or transparent with just
   * a border. See the Custom Colors story below for more information about how
   * a button's filled status affects how its color props behave.
   */
  filled: PropTypes.bool,
  /**
   * A stateful color set to use for the background of the button. The
   * supported states are `default`, `hover`, `active`, and `disabled`; if
   * a string is provided it is considered shorthand for the `default` state
   * color. Each color value can be either the name of a color provided by this
   * library (e.g., `altblack-80`) or a valid CSS color (e.g., `red`,
   * `#f04444`). Note that if the button is not filled this color set is
   * ignored and the background will be transparent.
   */
  bg: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    default: PropTypes.string,
    hover: PropTypes.string,
    active: PropTypes.string,
    disabled: PropTypes.string
  })]),
  /**
   * A stateful color set to use for the foreground of the button. The
   * supported states are `default`, `hover`, `active`, and `disabled`; if
   * a string is provided it is considered shorthand for the `default` state
   * color. Each color value can be either the name of a color provided by this
   * library (e.g., `altblack-80`) or a valid CSS color (e.g., `red`,
   * `#f04444`).
   */
  fg: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    default: PropTypes.string,
    hover: PropTypes.string,
    active: PropTypes.string,
    disabled: PropTypes.string
  })]),
  /**
   * A stateful color set to use for the border color of the button. The
   * supported states are `default`, `hover`, `active`, and `disabled`; if
   * a string is provided it is considered shorthand for the `default` state
   * color. Each color value can be either the name of a color provided by this
   * library (e.g., `altblack-80`) or a valid CSS color (e.g., `red`,
   * `#f04444`).
   */
  border: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    default: PropTypes.string,
    hover: PropTypes.string,
    active: PropTypes.string,
    disabled: PropTypes.string
  })]),
  /**
   * The level of shadow that the button should have, if any. Only use shadows
   * on buttons that are filled. See documentation on our shadow levels for
   * guidance on which level to use.
   */
  shadow: PropTypes.oneOf(['000', '100', '200', '300', '400']),
  /**
   * Title text to display when the user hovers over the button. This can be
   * used to provide more information about what the button does or why the
   * button is currently disabled.
   */
  title: PropTypes.string,
  /**
   * The padding of the button. Padding can be specified as one spacing value
   * that gets used on all sides, separate `x` and `y` values, or completely
   * separate `trbl` values. The values correspond to levels of our spacing
   * scale (e.g., `"4"` corresponds to `$spacing-4`). If you don't specify any
   * padding some default padding is applied, but if you specify any padding at
   * all the default padding is removed.
   *
   * Button padding can also be specified as a responsive value. See our guide
   * on our standard styling props for more details.
   */
  padding: CustomPropTypes.responsive(PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
    x: PropTypes.string,
    y: PropTypes.string
  }), PropTypes.shape({
    t: PropTypes.string,
    r: PropTypes.string,
    b: PropTypes.string,
    l: PropTypes.string
  })]))
};
export default Button;