import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _objectSpread from "@babel/runtime/helpers/objectSpread";

/**
 * Web Radio Component
 *
 */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import keycode from 'keycode';
import { isTrue, registerElement, validateDOMAttributes, dispatchCustomElementEvent } from '../../shared/component-helper';
import FormLabel from '../form-label/FormLabel';
import FormStatus from '../form-status/FormStatus';
import RadioGroup from './RadioGroup';
import RadioGroupContext from './RadioGroupContext';
const renderProps = {
  on_change: null,
  on_state_update: null
};
export const propTypes = {
  label: PropTypes.string,
  label_position: PropTypes.oneOf(['left', 'right']),
  title: PropTypes.string,
  checked: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  disabled: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  id: PropTypes.string,
  group: PropTypes.string,
  status: PropTypes.string,
  status_state: PropTypes.string,
  status_animation: PropTypes.string,
  value: PropTypes.string,
  attributes: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  readOnly: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
  class: PropTypes.string,
  /// React props
  className: PropTypes.string,
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
  // Web Component props
  custom_element: PropTypes.object,
  custom_method: PropTypes.func,
  on_change: PropTypes.func,
  on_state_update: PropTypes.func
};
export const defaultProps = _objectSpread({
  label: null,
  label_position: 'right',
  title: null,
  checked: null,
  disabled: false,
  id: null,
  group: null,
  status: null,
  status_state: 'error',
  status_animation: null,
  value: '',
  attributes: null,
  readOnly: false,
  class: null,
  // React props
  className: null,
  children: null,
  // Web Component props
  custom_element: null,
  custom_method: null
}, renderProps);
/**
 * The radio component is our enhancement of the classic radio button.
 */

var _ref2 =
/*#__PURE__*/
React.createElement("span", {
  "aria-hidden": true,
  className: "dnb-radio__button"
});

var _ref3 =
/*#__PURE__*/
React.createElement("span", {
  className: "dnb-radio__focus"
});

var _ref4 =
/*#__PURE__*/
React.createElement("span", {
  className: "dnb-radio__dot"
});

export default class Radio extends Component {
  static enableWebComponent() {
    registerElement(Radio.tagName, Radio, defaultProps);
  }

  static getDerivedStateFromProps(props, state) {
    if (state._listenForPropChanges) {
      state.checked = Radio.parseChecked(props.checked);
    }

    state._listenForPropChanges = true;
    return state;
  }

  constructor(props) {
    super(props);

    _defineProperty(this, "onKeyDownHandler", event => {
      // only have key support if there is only a single radio
      if (this.isInNoGroup()) {
        switch (keycode(event)) {
          case 'enter':
            this.onChangeHandler(event);
            break;
        }
      } else {
        // else we only use the native support, and don't want space support
        // because only arrow keys has to be used
        switch (keycode(event)) {
          case 'space':
            event.preventDefault();
            break;
        }
      }

      dispatchCustomElementEvent(this, 'on_key_down', {
        event
      });
    });

    _defineProperty(this, "onChangeHandler", event => {
      if (isTrue(this.props.readOnly)) {
        return event.preventDefault();
      }

      const value = event.target.value;
      const checked = !this.state.checked; // delay in case we have a props group only

      if (this.isPlainGroup()) {
        // in case we have a false "hasContext" but a "group"
        // then we have to use a delay, to overwrite the uncrontrolled state
        setTimeout(() => {
          this.setState({
            checked,
            _listenForPropChanges: false
          }, () => this.callOnChange({
            value,
            checked
          }));
        }, 1);
      } else {
        this.setState({
          checked,
          _listenForPropChanges: false
        });
        this.callOnChange({
          value,
          checked
        });
      }
    });

    _defineProperty(this, "isContextGroupOrSingle", () => typeof this.context.value !== 'undefined' && !this.props.group);

    _defineProperty(this, "isPlainGroup", () => typeof this.context.value === 'undefined' && this.props.group);

    _defineProperty(this, "isInNoGroup", () => typeof this.context.value === 'undefined' && !this.props.group);

    _defineProperty(this, "onClickHandler", event => {
      if (isTrue(this.props.readOnly)) {
        return event.preventDefault();
      } // only have click support if there are more plain radio


      if (!this.isPlainGroup()) {
        return;
      }

      const value = event.target.value;
      const checked = event.target.checked;
      this.callOnChange({
        value,
        checked
      });
    });

    _defineProperty(this, "callOnChange", (_ref) => {
      let {
        value,
        checked
      } = _ref;
      const {
        group
      } = this.props;

      if (this.context.onChange) {
        this.context.onChange({
          value
        });
      }

      dispatchCustomElementEvent(this, 'on_change', {
        group,
        checked,
        value
      }); // help firefox and safari to have an correct state after a click

      if (this._refInput.current) {
        this._refInput.current.focus();
      }
    });

    _defineProperty(this, "onMouseOutHandler", event => {
      dispatchCustomElementEvent(this, 'on_mouse_out', {
        event
      }); // this way we keep the new state after the user changed the state, without getting the error state back vissually

      if (this.props.status && this.props.status_state === 'error') {
        return;
      }

      if (this._refInput.current) {
        this._refInput.current.blur();
      }
    });

    this._refInput = React.createRef();
    this._id = props.id || "dnb-radio-".concat(Math.round(Math.random() * 999)); // cause we need an id anyway

    this.state = {
      _listenForPropChanges: true
    };
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (Radio.parseChecked(this.props.checked) !== Radio.parseChecked(nextProps.checked)) {
      const {
        checked
      } = nextState;
      dispatchCustomElementEvent(this, 'on_state_update', {
        checked
      });
    }

    return true;
  }

  render() {
    const _this$props = this.props,
          {
      status,
      status_state,
      status_animation,
      label,
      label_position,
      title,
      readOnly,
      className,
      class: _className,
      id: _id,
      // eslint-disable-line
      group: _group,
      // eslint-disable-line
      value: _value,
      // eslint-disable-line
      checked: _checked,
      // eslint-disable-line
      disabled: _disabled,
      // eslint-disable-line
      attributes,
      // eslint-disable-line
      children,
      // eslint-disable-line
      on_change,
      // eslint-disable-line
      on_state_update,
      // eslint-disable-line
      custom_method,
      // eslint-disable-line
      custom_element
    } = _this$props,
          rest = _objectWithoutProperties(_this$props, ["status", "status_state", "status_animation", "label", "label_position", "title", "readOnly", "className", "class", "id", "group", "value", "checked", "disabled", "attributes", "children", "on_change", "on_state_update", "custom_method", "custom_element"]);

    let {
      checked
    } = this.state;
    let {
      value,
      group,
      disabled
    } = this.props;
    const hasContext = typeof this.context.value !== 'undefined';

    if (hasContext) {
      if (this.context.value !== null) {
        checked = this.context.value === value;
      }

      group = this.context.name;
      disabled = isTrue(this.context.disabled);
    }

    const id = this._id;
    const showStatus = status && status !== 'error';
    const classes = classnames('dnb-radio', status && "dnb-radio__status--".concat(status_state), label_position && "dnb-radio--label-position-".concat(label_position), className, _className);

    const inputParams = _objectSpread({
      role: hasContext || group ? 'radio' : null,
      type: hasContext || group ? 'radio' : 'checkbox'
    }, rest, {
      onMouseOut: this.onMouseOutHandler // for resetting the button to the default state

    });

    if (showStatus) {
      inputParams['aria-describedby'] = id + '-status';
    }

    if (label) {
      inputParams['aria-labelledby'] = id + '-label';
    }

    if (readOnly) {
      inputParams['aria-readonly'] = inputParams.readOnly = true;
    } // also used for code markup simulation


    validateDOMAttributes(this.props, inputParams);
    return React.createElement(React.Fragment, null, React.createElement("span", {
      className: classes
    }, label && React.createElement(FormLabel, {
      id: id + '-label',
      for_id: id,
      "aria-hidden": !this.isInNoGroup(),
      text: label,
      disabled: isTrue(disabled)
    }), React.createElement("span", {
      className: "dnb-radio__shell"
    }, React.createElement("input", _extends({
      type: "checkbox",
      value: value,
      id: id,
      name: group,
      className: "dnb-radio__input",
      checked: checked,
      "aria-checked": checked,
      title: title,
      "aria-label": title,
      disabled: isTrue(disabled),
      ref: this._refInput
    }, inputParams, {
      onChange: this.onChangeHandler,
      onClick: this.onClickHandler,
      onKeyDown: this.onKeyDownHandler
    })), _ref2, _ref3, _ref4)), showStatus && React.createElement(FormStatus, {
      text: status,
      status: status_state,
      text_id: id + '-status' // used for "aria-describedby"
      ,
      animation: status_animation
    }));
  }

}

_defineProperty(Radio, "tagName", 'dnb-radio');

_defineProperty(Radio, "defaultProps", defaultProps);

_defineProperty(Radio, "renderProps", renderProps);

_defineProperty(Radio, "contextType", RadioGroupContext);

_defineProperty(Radio, "Group", RadioGroup);

_defineProperty(Radio, "parseChecked", state => /true|on/.test(String(state)));

Radio.propTypes = process.env.NODE_ENV !== "production" ? propTypes : {};