import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Validator from '../util/easyValidator';
import FormContext from './FormContext';
import render from './fieldRender';
export default (function () {
  var defaultValues = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var defaultSchema = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {
    inline: false,
    labelLayout: {
      size: 10
    },
    size: 'medium',
    contentLayout: {
      size: 8
    }
  };
  return function (ComposedComponent) {
    var Form =
    /*#__PURE__*/
    function (_Component) {
      _inherits(Form, _Component);

      _createClass(Form, null, [{
        key: "getDerivedStateFromProps",
        value: function getDerivedStateFromProps(nextProps, prevState) {
          var values = nextProps.values;
          var nextState = {};

          if (values !== prevState.lastValues) {
            Object.assign(nextState, {
              values: values,
              lastValues: nextProps.values
            });
          }

          return nextState;
        }
      }]);

      function Form(props, context) {
        var _this;

        _classCallCheck(this, Form);

        _this = _possibleConstructorReturn(this, _getPrototypeOf(Form).call(this, props, context));

        _defineProperty(_assertThisInitialized(_this), "getFieldValue", function () {
          var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
          var onChange = _this.props.onChange;
          var values;
          _this.isPristine = false;

          _this.setState(function (state) {
            values = _objectSpread({}, state.values, value);
            if (onChange) onChange(value, values);
            return {
              values: values
            };
          });
        });

        _defineProperty(_assertThisInitialized(_this), "handleFieldChange", function () {
          var value = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
          var onFormChange = options.onFormChange;

          if (onFormChange) {
            onFormChange(_this.props, value, _this.getFieldValue);
          } else {
            _this.getFieldValue(value);
          }
        });

        _defineProperty(_assertThisInitialized(_this), "initialize", function () {
          var onFormReset = options.onFormReset;

          _this.validator.cancelAll();

          _this.isPristine = true;

          if (onFormReset) {
            onFormReset(_this.props, _this.originalData, _this.updateValues);
          } else {
            _this.updateValues(_this.originalData);
          }

          _this.setState({
            errors: {},
            validatings: {}
          });
        });

        _defineProperty(_assertThisInitialized(_this), "updateErrors", function (newErrors) {
          _this.setState({
            errors: newErrors
          });
        });

        _defineProperty(_assertThisInitialized(_this), "updateFieldError", function (name, newError) {
          _this.setState(function (state) {
            return {
              errors: Object.assign({}, state.errors, _defineProperty({}, name, newError))
            };
          });
        });

        _defineProperty(_assertThisInitialized(_this), "updateValues", function (newValues) {
          _this.setState({
            values: newValues
          });
        });

        _defineProperty(_assertThisInitialized(_this), "updateFieldValue", function (name, newValue) {
          var shouldValidate = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
          _this.isPristine = false;

          _this.setState(function (state) {
            return {
              values: Object.assign({}, state.values, _defineProperty({}, name, newValue))
            };
          });

          if (shouldValidate) {
            if (_this.fieldValidators[name]) {
              _this.fieldValidators[name].handleValidate(newValue);
            } else {
              _this.validateItem(name, newValue);
            }
          }
        });

        _defineProperty(_assertThisInitialized(_this), "register", function (name, field) {
          _this.fieldValidators[name] = field;
        });

        _defineProperty(_assertThisInitialized(_this), "unRegister", function (name) {
          _this.fieldValidators[name] = null;
        });

        _defineProperty(_assertThisInitialized(_this), "updateSchema", function (newSchema) {
          _this.schema = newSchema;

          _this.validator.setSchema(newSchema);
        });

        _defineProperty(_assertThisInitialized(_this), "validateItem", function (name, value) {
          var _this$validator;

          _this.setState(function (state) {
            return {
              validatings: _objectSpread({}, state.validatings, _defineProperty({}, name, true))
            };
          });

          var values = _this.state.values;
          var target = Object.assign({}, values, value != null ? _defineProperty({}, name, value) : {});

          for (var _len = arguments.length, other = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
            other[_key - 2] = arguments[_key];
          }

          var validation = (_this$validator = _this.validator).validateItem.apply(_this$validator, [target, name, function (errors) {
            _this.setState(function (state) {
              return {
                errors: _objectSpread({}, state.errors, _defineProperty({}, name, errors)),
                validatings: _objectSpread({}, state.validatings, _defineProperty({}, name, false))
              };
            });
          }, target].concat(other));

          return validation;
        });

        _defineProperty(_assertThisInitialized(_this), "validateAll", function () {
          return Promise.all(Object.keys(_this.schema).map(function (fieldName) {
            return _this.fieldValidators[fieldName] ? _this.fieldValidators[fieldName].handleValidate() : _this.validateItem(fieldName);
          }));
        });

        _defineProperty(_assertThisInitialized(_this), "submit", function (onSubmitSuccess, onSubmitFail) {
          return function () {
            _this.setState({
              isSubmitting: true
            });

            var values = _this.state.values;
            return _this.validateAll().then(function (results) {
              var errors = {};
              results.forEach(function (result) {
                errors[result.fieldName] = result.errors;
              });

              if (Object.values(errors).filter(function (m) {
                return m && m.length > 0;
              }).length > 0) {
                if (onSubmitFail) {
                  onSubmitFail(errors);
                }
              } else if (onSubmitSuccess) {
                onSubmitSuccess(values);
              }
            }).then(function () {
              _this.setState({
                isSubmitting: false
              });
            }, function () {
              _this.setState({
                isSubmitting: false
              });
            });
          };
        });

        var _values = props.values,
            schema = props.schema,
            inline = props.inline,
            size = props.size;
        var getValueFromEvent = options.getValueFromEvent,
            fieldRender = options.fieldRender,
            contentLayout = options.contentLayout,
            labelLayout = options.labelLayout;
        _this.state = {
          values: _this.originalData,
          errors: {},
          validatings: {},
          isSubmitting: false,

          /* eslint-disable */
          contentLayout: contentLayout,
          labelLayout: labelLayout,
          getValueFromEvent: getValueFromEvent,
          inline: inline,
          size: size,
          onFieldChange: _this.handleFieldChange,
          validateItem: _this.validateItem,
          render: fieldRender || render,
          register: _this.register,
          unRegister: _this.unRegister
          /* eslint-enble */

        };
        _this.isPristine = true;
        _this.fieldValidators = {};
        _this.originalData = _values;
        _this.schema = schema;
        _this.validator = new Validator(schema, options.validationOption);
        return _this;
      }

      _createClass(Form, [{
        key: "componentDidUpdate",
        value: function componentDidUpdate(prevProps) {
          var schema = this.props.schema;

          if (schema !== prevProps.schema) {
            this.validator = new Validator(schema, options.validationOption);
            this.schema = schema;
          }
        }
      }, {
        key: "render",
        value: function render() {
          var _this$props = this.props,
              onFormChange = _this$props.onFormChange,
              onChange = _this$props.onChange,
              forwardedRef = _this$props.forwardedRef,
              other = _objectWithoutProperties(_this$props, ["onFormChange", "onChange", "forwardedRef"]);

          var _this$state = this.state,
              validatings = _this$state.validatings,
              errors = _this$state.errors,
              values = _this$state.values,
              isSubmitting = _this$state.isSubmitting;
          var isValidating = Object.values(validatings).filter(function (msg) {
            return msg;
          }).length > 0;
          var isValid = Object.values(errors).filter(function (msg) {
            return msg && msg.length > 0;
          }).length <= 0;
          return React.createElement(FormContext.Provider, {
            value: this.state
          }, React.createElement(ComposedComponent, _extends({}, other, {
            ref: forwardedRef,
            validatings: validatings,
            errors: errors,
            values: values,
            isSubmitting: isSubmitting,
            updateFieldError: this.updateFieldError,
            updateErrors: this.updateErrors,
            updateFieldValue: this.updateFieldValue,
            updateValues: this.updateValues,
            updateSchema: this.updateSchema,
            isValidating: isValidating,
            isValid: isValid,
            validateAll: this.validateAll,
            validateItem: this.validateItem,
            initialize: this.initialize,
            submit: this.submit,
            isPristine: this.isPristine
          })));
        }
      }], [{
        key: "getDerivedStateFromProps",
        value: function getDerivedStateFromProps(nextProps, prevState) {
          var values = nextProps.values;
          var nextState = {};

          if (values !== prevState.lastValues) {
            Object.assign(nextState, {
              values: values,
              lastValues: nextProps.values
            });
          }

          return nextState;
        }
      }]);

      return Form;
    }(Component);

    _defineProperty(Form, "defaultProps", {
      values: defaultValues,
      schema: defaultSchema,
      inline: options.inline,
      size: options.size || 'medium'
    });

    _defineProperty(Form, "propTypes", {
      /**
       * The values of the form.
       */
      values: PropTypes.object,
      schema: PropTypes.object,

      /**
       * Handler while value of any field is changed
       * @param {object} changedValue The value of the changed input.
       * @param {object} values The values of the whole form.
       */
      onChange: PropTypes.func
    });

    function forwardRef(props, ref) {
      return React.createElement(Form, _extends({}, props, {
        forwardedRef: ref
      }));
    } // Give this component a more helpful display name in DevTools.


    var name = ComposedComponent.displayName || ComposedComponent.name;
    forwardRef.displayName = "EasyForm(".concat(name, ")");
    return React.forwardRef(forwardRef);
  };
});