/* eslint-disable react/button-has-type */
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import classNamesBind from 'classnames/bind';
import ThemeContext from 'terra-theme-context';
import * as KeyCode from 'keycode-js';
import styles from './_ShowHideButton.module.scss';

const cx = classNamesBind.bind(styles);

const propTypes = {
  /**
   * Callback function triggered when clicked.
   */
  onClick: PropTypes.func,
  /**
   * Callback function triggered when button loses focus.
   */
  onBlur: PropTypes.func,
  /**
   * Callback function triggered when button gains focus.
   */
  onFocus: PropTypes.func,
  /**
   * Callback function triggered when key is pressed.
   */
  onKeyDown: PropTypes.func,
  /**
   * Callback function triggered when key is released.
   */
  onKeyUp: PropTypes.func,
  /**
   * Callback ref to pass into the dom element.
   */
  refCallback: PropTypes.func,
  /**
   * Sets the button text.
   */
  text: PropTypes.string.isRequired,
};

const defaultProps = {
  refCallback: undefined,
};

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = { active: false, focused: false };
    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleKeyUp = this.handleKeyUp.bind(this);
    this.handleOnBlur = this.handleOnBlur.bind(this);
  }

  handleOnBlur(event) {
    this.setState({ focused: false });

    if (this.props.onBlur) {
      this.props.onBlur(event);
    }
  }

  handleKeyDown(event) {
    // Add active state to FF browser
    if (event.nativeEvent.keyCode === KeyCode.KEY_SPACE) {
      this.setState({ active: true });
      this.setState({ focused: true });
    } else if (event.nativeEvent.keyCode === KeyCode.KEY_RETURN) { // Add focus styles for keyboard navigation
      this.setState({ focused: true });
    }

    if (this.props.onKeyDown) {
      this.props.onKeyDown(event);
    }
  }

  handleKeyUp(event) {
    // Remove active state from FF broswers
    if (event.nativeEvent.keyCode === KeyCode.KEY_SPACE) {
      this.setState({ active: false });
    }

    // Apply focus styles for keyboard navigation
    if (event.nativeEvent.keyCode === KeyCode.KEY_TAB) {
      this.setState({ focused: true });
    }

    if (this.props.onKeyUp) {
      this.props.onKeyUp(event);
    }
  }

  render() {
    const {
      text,
      onClick,
      onBlur,
      onFocus,
      onKeyDown,
      onKeyUp,
      refCallback,
      ...customProps
    } = this.props;

    const theme = this.context;

    const buttonClasses = classNames(
      cx([
        'button',
        { 'is-active': this.state.active },
        { 'is-focused': this.state.focused },
        theme.className,
      ]),
      customProps.className,
    );

    return (
      <button
        {...customProps}
        className={buttonClasses}
        type="button"
        onKeyDown={this.handleKeyDown}
        onKeyUp={this.handleKeyUp}
        onBlur={this.handleOnBlur}
        onClick={onClick}
        onFocus={onFocus}
        ref={refCallback}
      >
        <span className={cx('inner')}>
          <span className={cx('text')}>
            {text}
          </span>
          <span className={cx('icon-holder')}>
            <span className={cx('icon')} />
          </span>
        </span>
      </button>
    );
  }
}

Button.propTypes = propTypes;
Button.defaultProps = defaultProps;
Button.contextType = ThemeContext;

export default Button;
