import React, { forwardRef } from "react";
import cn from "classnames";
import PropTypes from "prop-types";
import { AsComponent, AsPropsWithChildren } from "../utils/asComponent";

export type ButtonVariants =
  | "primary"
  | "secondary"
  | "success"
  | "danger"
  | "warning"
  | "info"
  | "dark"
  | "light"
  | "link"
  | "white"
  | "outline-primary"
  | "outline-secondary"
  | "outline-success"
  | "outline-danger"
  | "outline-warning"
  | "outline-info"
  | "outline-dark"
  | "outline-light"
  | "outline-white";

export interface IButtonProps extends AsPropsWithChildren, React.HTMLAttributes<HTMLElement> {
  disabled?: boolean;
  variant?: ButtonVariants;
  size?: "lg" | "sm";
  type?: "button" | "reset" | "submit" | "cancel";
  href?: string;
  value?: string;
  block?: boolean;
  active?: boolean;
  onClick?: (event: React.SyntheticEvent) => void;
  onKeyPress?: (event: React.KeyboardEvent) => void;
}

type Button = AsComponent<"button", IButtonProps>;
// Destructuring props to exclude `as` and `type` to avoid passing them to elements
const Button: Button = forwardRef(
  ({ className, variant, block, size, active, as: Component = "button", ...props }, ref) => {
    const classes = cn(
      className,
      "btn",
      `btn-${variant}`,
      active && "active",
      block && "btn-block",
      props.disabled && "disabled",
      size && `btn-${size}`
    );

    return <Component {...props} ref={ref} className={classes} />;
  }
);

Button.displayName = "Button";
Button.defaultProps = {
  variant: "primary",
  type: "button"
};
Button.propTypes = {
  className: PropTypes.string,
  disabled: PropTypes.bool,
  size: PropTypes.oneOf(["lg", "sm"]),
  variant: PropTypes.oneOf([
    "primary",
    "secondary",
    "success",
    "danger",
    "warning",
    "info",
    "dark",
    "light",
    "link",
    "white",
    "outline-primary",
    "outline-secondary",
    "outline-success",
    "outline-danger",
    "outline-warning",
    "outline-info",
    "outline-dark",
    "outline-light",
    "outline-white"
  ]),
  type: PropTypes.oneOf(["button", "reset", "submit", "cancel"]),
  href: PropTypes.string,
  value: PropTypes.string,
  block: PropTypes.bool,
  active: PropTypes.bool,
  onClick: PropTypes.func
};

export default Button;
