import _readOnlyError from "@babel/runtime/helpers/esm/readOnlyError";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _extends from "@babel/runtime/helpers/esm/extends";
import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
var _excluded = ["validate", "validationSchema"];
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
import cloneDeep from 'lodash/cloneDeep';
import * as React from 'react';
import isEqual from 'react-fast-compare';
import { connect } from './connect';
import { getIn, isEmptyArray, isEmptyChildren, isFunction, isObject, setIn } from './utils';
/**
 * Some array helpers!
 */
export var move = function move(array, from, to) {
  var copy = copyArrayLike(array);
  var value = copy[from];
  copy.splice(from, 1);
  copy.splice(to, 0, value);
  return copy;
};
export var swap = function swap(arrayLike, indexA, indexB) {
  var copy = copyArrayLike(arrayLike);
  var a = copy[indexA];
  copy[indexA] = copy[indexB];
  copy[indexB] = a;
  return copy;
};
export var insert = function insert(arrayLike, index, value) {
  var copy = copyArrayLike(arrayLike);
  copy.splice(index, 0, value);
  return copy;
};
export var replace = function replace(arrayLike, index, value) {
  var copy = copyArrayLike(arrayLike);
  copy[index] = value;
  return copy;
};
var copyArrayLike = function copyArrayLike(arrayLike) {
  if (!arrayLike) {
    return [];
  } else if (Array.isArray(arrayLike)) {
    return _toConsumableArray(arrayLike);
  } else {
    var maxIndex = Object.keys(arrayLike).map(function (key) {
      return parseInt(key);
    }).reduce(function (max, el) {
      return el > max ? el : max;
    }, 0);
    return Array.from(_extends({}, arrayLike, {
      length: maxIndex + 1
    }));
  }
};
var createAlterationHandler = function createAlterationHandler(alteration, defaultFunction) {
  var fn = typeof alteration === 'function' ? alteration : defaultFunction;
  return function (data) {
    if (Array.isArray(data) || isObject(data)) {
      var clone = copyArrayLike(data);
      return fn(clone);
    }

    // This can be assumed to be a primitive, which
    // is a case for top level validation errors
    return data;
  };
};
var FieldArrayInner = /*#__PURE__*/function (_React$Component) {
  function FieldArrayInner(props) {
    var _this;
    _classCallCheck(this, FieldArrayInner);
    _this = _callSuper(this, FieldArrayInner, [props]);
    // We need TypeScript generics on these, so we'll bind them in the constructor
    // @todo Fix TS 3.2.1
    _defineProperty(_this, "updateArrayField", function (fn, alterTouched, alterErrors) {
      var _this$props = _this.props,
        name = _this$props.name,
        setFormikState = _this$props.formik.setFormikState;
      setFormikState(function (prevState) {
        var updateErrors = createAlterationHandler(alterErrors, fn);
        var updateTouched = createAlterationHandler(alterTouched, fn);

        // values fn should be executed before updateErrors and updateTouched,
        // otherwise it causes an error with unshift.
        var values = setIn(prevState.values, name, fn(getIn(prevState.values, name)));
        var fieldError = alterErrors ? updateErrors(getIn(prevState.errors, name)) : undefined;
        var fieldTouched = alterTouched ? updateTouched(getIn(prevState.touched, name)) : undefined;
        if (isEmptyArray(fieldError)) {
          fieldError = undefined;
        }
        if (isEmptyArray(fieldTouched)) {
          fieldTouched = undefined;
        }
        return _extends({}, prevState, {
          values: values,
          errors: alterErrors ? setIn(prevState.errors, name, fieldError) : prevState.errors,
          touched: alterTouched ? setIn(prevState.touched, name, fieldTouched) : prevState.touched
        });
      });
    });
    _defineProperty(_this, "push", function (value) {
      return _this.updateArrayField(function (arrayLike) {
        return [].concat(_toConsumableArray(copyArrayLike(arrayLike)), [cloneDeep(value)]);
      }, false, false);
    });
    _defineProperty(_this, "handlePush", function (value) {
      return function () {
        return _this.push(value);
      };
    });
    _defineProperty(_this, "swap", function (indexA, indexB) {
      return _this.updateArrayField(function (array) {
        return swap(array, indexA, indexB);
      }, true, true);
    });
    _defineProperty(_this, "handleSwap", function (indexA, indexB) {
      return function () {
        return _this.swap(indexA, indexB);
      };
    });
    _defineProperty(_this, "move", function (from, to) {
      return _this.updateArrayField(function (array) {
        return move(array, from, to);
      }, true, true);
    });
    _defineProperty(_this, "handleMove", function (from, to) {
      return function () {
        return _this.move(from, to);
      };
    });
    _defineProperty(_this, "insert", function (index, value) {
      return _this.updateArrayField(function (array) {
        return insert(array, index, value);
      }, function (array) {
        return insert(array, index, null);
      }, function (array) {
        return insert(array, index, null);
      });
    });
    _defineProperty(_this, "handleInsert", function (index, value) {
      return function () {
        return _this.insert(index, value);
      };
    });
    _defineProperty(_this, "replace", function (index, value) {
      return _this.updateArrayField(function (array) {
        return replace(array, index, value);
      }, false, false);
    });
    _defineProperty(_this, "handleReplace", function (index, value) {
      return function () {
        return _this.replace(index, value);
      };
    });
    _defineProperty(_this, "unshift", function (value) {
      var length = -1;
      _this.updateArrayField(function (array) {
        var arr = array ? [value].concat(_toConsumableArray(array)) : [value];
        length = arr.length;
        return arr;
      }, function (array) {
        return array ? [null].concat(_toConsumableArray(array)) : [null];
      }, function (array) {
        return array ? [null].concat(_toConsumableArray(array)) : [null];
      });
      return length;
    });
    _defineProperty(_this, "handleUnshift", function (value) {
      return function () {
        return _this.unshift(value);
      };
    });
    _defineProperty(_this, "handleRemove", function (index) {
      return function () {
        return _this.remove(index);
      };
    });
    _defineProperty(_this, "handlePop", function () {
      return function () {
        return _this.pop();
      };
    });
    _this.remove = _this.remove.bind(_this);
    _this.pop = _this.pop.bind(_this);
    return _this;
  }
  _inherits(FieldArrayInner, _React$Component);
  return _createClass(FieldArrayInner, [{
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      if (this.props.validateOnChange && this.props.formik.validateOnChange && !isEqual(getIn(prevProps.formik.values, prevProps.name), getIn(this.props.formik.values, this.props.name))) {
        this.props.formik.validateForm(this.props.formik.values);
      }
    }
  }, {
    key: "remove",
    value: function remove(index) {
      // We need to make sure we also remove relevant pieces of `touched` and `errors`
      var result;
      this.updateArrayField(
      // so this gets call 3 times
      function (array) {
        var copy = array ? copyArrayLike(array) : [];
        if (!result) {
          result = copy[index];
        }
        if (isFunction(copy.splice)) {
          copy.splice(index, 1);
        }
        // if the array only includes undefined values we have to return an empty array
        return isFunction(copy.every) ? copy.every(function (v) {
          return v === undefined;
        }) ? [] : copy : copy;
      }, true, true);
      return result;
    }
  }, {
    key: "pop",
    value: function pop() {
      // Remove relevant pieces of `touched` and `errors` too!
      var result;
      this.updateArrayField(
      // so this gets call 3 times
      function (array) {
        var tmp = array.slice();
        if (!result) {
          result = tmp && tmp.pop && tmp.pop();
        }
        return tmp;
      }, true, true);
      return result;
    }
  }, {
    key: "render",
    value: function render() {
      var arrayHelpers = {
        push: this.push,
        pop: this.pop,
        swap: this.swap,
        move: this.move,
        insert: this.insert,
        replace: this.replace,
        unshift: this.unshift,
        remove: this.remove,
        handlePush: this.handlePush,
        handlePop: this.handlePop,
        handleSwap: this.handleSwap,
        handleMove: this.handleMove,
        handleInsert: this.handleInsert,
        handleReplace: this.handleReplace,
        handleUnshift: this.handleUnshift,
        handleRemove: this.handleRemove
      };
      var _this$props2 = this.props,
        component = _this$props2.component,
        render = _this$props2.render,
        children = _this$props2.children,
        name = _this$props2.name,
        _this$props2$formik = _this$props2.formik,
        _validate = _this$props2$formik.validate,
        _validationSchema = _this$props2$formik.validationSchema,
        restOfFormik = _objectWithoutProperties(_this$props2$formik, _excluded);
      var props = _extends({}, arrayHelpers, {
        form: restOfFormik,
        name: name
      });
      return component ? /*#__PURE__*/React.createElement(component, props) : render ? render(props) : children // children come last, always called
      ? typeof children === 'function' ? children(props) : !isEmptyChildren(children) ? React.Children.only(children) : null : null;
    }
  }]);
}(React.Component);
_defineProperty(FieldArrayInner, "defaultProps", {
  validateOnChange: true
});
export var FieldArray = connect(FieldArrayInner);