import _toConsumableArray from "@babel/runtime/helpers/esm/toConsumableArray";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";

var Validator =
/*#__PURE__*/
function () {
  function Validator(schema) {
    var _this = this;

    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {
      first: true,
      concurrent: false
    };

    _classCallCheck(this, Validator);

    _defineProperty(this, "transformToPromise", function (rule, target, errors) {
      for (var _len = arguments.length, other = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
        other[_key - 3] = arguments[_key];
      }

      if (typeof rule.validator !== 'function') {
        throw 'invalid validator';
      }

      var ruleReturn = rule.validator.apply(rule, [target].concat(other));

      if (!ruleReturn || !ruleReturn.then) {
        ruleReturn = ruleReturn ? Promise.resolve(ruleReturn) : Promise.reject(ruleReturn);
      }

      var data = {
        errors: errors,
        target: target
      };
      return ruleReturn.then(function (promiseValue) {
        return Object.assign(data, {
          promiseValue: promiseValue
        });
      }, function (promiseValue) {
        data.errors = _this.messageHandler.apply(_this, [errors, rule.message, target, promiseValue].concat(other));
        return Promise.reject(Object.assign(data, {
          promiseValue: promiseValue
        }));
      });
    });

    this.lastValidator = {};
    this.schema = schema;
    this.options = options;
  }

  _createClass(Validator, [{
    key: "validate",
    value: function validate(target, rules) {
      var _this2 = this;

      var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};

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

      var errors = [];
      var promiseQueue;

      if (!rules || rules.length < 1) {
        return Promise.resolve({
          value: target
        });
      }

      if (!Array.isArray(rules)) {
        rules = [rules];
      }

      if (options.concurrent) {
        promiseQueue = Promise.all(rules.map(function (rule) {
          return _this2.transformToPromise.apply(_this2, [rule, target, errors].concat(other)).then(function (value) {
            return value;
          }, options.first ? function (value) {
            return value;
          } : null);
        }));
      } else {
        promiseQueue = rules.reduce(function (queue, rule) {
          return queue.then(function () {
            return _this2.transformToPromise.apply(_this2, [rule, target, errors].concat(other));
          }, !options.first ? function () {
            return _this2.transformToPromise.apply(_this2, [rule, target, errors].concat(other));
          } : null);
        }, Promise.resolve());
      }

      return promiseQueue;
    }
  }, {
    key: "validateItem",
    value: function validateItem(source, fieldName, callback) {
      var _this3 = this;

      var rules = this.schema[fieldName];
      var targets = source[fieldName];

      if (rules && rules.withFields) {
        var fields = Array.isArray(rules.withFields) ? rules.withFields : [rules.withFields];
        targets = [fieldName].concat(_toConsumableArray(fields)).map(function (name) {
          return source[name];
        });
      }

      if (rules && rules.rules) {
        rules = rules.rules;
      }

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

      var validation = this.validate.apply(this, [targets, rules, this.options].concat(other));
      this.lastValidator[fieldName] = validation;
      return validation.then(function (value) {
        if (value) {
          value.fieldName = fieldName;

          if (callback && _this3.lastValidator[fieldName] === validation) {
            _this3.lastValidator[fieldName] = null;
            callback(null, value.target);
          }
        }

        return value;
      }, function (value) {
        if (value) {
          value.fieldName = fieldName;

          if (callback && _this3.lastValidator[fieldName] === validation) {
            _this3.lastValidator[fieldName] = null;
            callback(value.errors, value.target);
          }
        }

        return value;
      });
    } // validateAll(source, callback, options = {}) {
    //   let hasError = false;
    //   const errors = {};
    //   const promises = [];
    //   (options.specificField || Object.keys(this.schema)).forEach(name => {
    //     promises.push(
    //       this.validateItem(source, name, fieldError => {
    //         errors[name] = fieldError;
    //         options.fieldCallback && options.fieldCallback(name, fieldError);
    //       }),
    //     );
    //   });
    //   return Promise.all(
    //     promises.map(p =>
    //       p.catch(v => {
    //         hasError = true;
    //         return v;
    //       }),
    //     ),
    //   ).then(() => {
    //     callback(errors, !hasError);
    //     return hasError ? null : errors;
    //   });
    // }

  }, {
    key: "messageHandler",
    value: function messageHandler(result, message, target, promiseValue) {
      if (typeof message === 'function') {
        for (var _len4 = arguments.length, other = new Array(_len4 > 4 ? _len4 - 4 : 0), _key4 = 4; _key4 < _len4; _key4++) {
          other[_key4 - 4] = arguments[_key4];
        }

        result.push("".concat(message.apply(void 0, [target, promiseValue].concat(other)) || 'Error!').trim());
      } else {
        result.push("".concat(message != null ? message : 'Error!').trim());
      }

      return result;
    }
  }, {
    key: "cancelItem",
    value: function cancelItem(name) {
      this.lastValidator[name] = null;
    }
  }, {
    key: "cancelAll",
    value: function cancelAll() {
      this.lastValidator = {};
    }
  }, {
    key: "setSchema",
    value: function setSchema(schema) {
      this.schema = schema;
    }
  }, {
    key: "setOptions",
    value: function setOptions(options) {
      this.options = options;
    }
  }]);

  return Validator;
}();

export { Validator as default };