'use strict';

var RawAsyncValidator = require('async-validator');
var vue = require('vue');
require('../../../../utils/index.cjs');
var valueUtil = require('./valueUtil.cjs');
var messages = require('./messages.cjs');
var is = require('../../../../utils/is.cjs');
var log = require('../../../../utils/log.cjs');

const AsyncValidator = RawAsyncValidator;
function replaceMessage(template, kv) {
  return template.replace(/\$\{\w+\}/g, (str) => {
    const key = str.slice(2, -1);
    return kv[key];
  });
}
async function validateRule(name, value, rule, options, messageVariables) {
  const cloneRule = { ...rule };
  delete cloneRule.ruleIndex;
  delete cloneRule.trigger;
  let subRuleField = null;
  if (cloneRule && cloneRule.type === "array" && cloneRule.defaultField) {
    subRuleField = cloneRule.defaultField;
    delete cloneRule.defaultField;
  }
  const validator = new AsyncValidator({
    [name]: [cloneRule]
  });
  const messages$1 = valueUtil.setValues({}, messages.defaultValidateMessages, options.validateMessages);
  validator.messages(messages$1);
  let result = [];
  try {
    await Promise.resolve(validator.validate({ [name]: value }, { ...options }));
  } catch (errObj) {
    if (errObj.errors) {
      result = errObj.errors.map(
        ({ message }, index) => is.isValidElement(message) ? vue.cloneVNode(message, { key: `error_${index}` }) : message
      );
    } else {
      console.error(errObj);
      result = [messages$1.default()];
    }
  }
  if (!result.length && subRuleField) {
    const subResults = await Promise.all(
      value.map(
        (subValue, i) => validateRule(`${name}.${i}`, subValue, subRuleField, options, messageVariables)
      )
    );
    return subResults.reduce((prev, errors) => [...prev, ...errors], []);
  }
  const kv = {
    ...rule,
    name,
    enum: (rule.enum || []).join(", "),
    ...messageVariables
  };
  const fillVariableResult = result.map((error) => {
    if (typeof error === "string")
      return replaceMessage(error, kv);
    return error;
  });
  return fillVariableResult;
}
function validateRules(namePath, value, rules, options, validateFirst, messageVariables) {
  const name = namePath.join(".");
  const filledRules = rules.map((currentRule, ruleIndex) => {
    const originValidatorFunc = currentRule.validator;
    const cloneRule = {
      ...currentRule,
      ruleIndex
    };
    if (originValidatorFunc) {
      cloneRule.validator = (rule, val, callback) => {
        let hasPromise = false;
        const wrappedCallback = (...args) => {
          Promise.resolve().then(() => {
            log.warning(
              !hasPromise,
              "Your validator function has already return a promise. `callback` will be ignored."
            );
            if (!hasPromise)
              callback(...args);
          });
        };
        const promise = originValidatorFunc(rule, val, wrappedCallback);
        hasPromise = promise && typeof promise.then === "function" && typeof promise.catch === "function";
        log.warning(hasPromise, "`callback` is deprecated. Please return a promise instead.");
        if (hasPromise) {
          promise.then(() => {
            callback();
          }).catch((err) => {
            callback(err || " ");
          });
        }
      };
    }
    return cloneRule;
  }).sort(({ warningOnly: w1, ruleIndex: i1 }, { warningOnly: w2, ruleIndex: i2 }) => {
    if (!!w1 === !!w2) {
      return i1 - i2;
    }
    if (w1)
      return 1;
    return -1;
  });
  let summaryPromise;
  if (validateFirst === true) {
    summaryPromise = new Promise(async (resolve, reject) => {
      for (let i = 0; i < filledRules.length; i += 1) {
        const rule = filledRules[i];
        const errors = await validateRule(name, value, rule, options, messageVariables);
        if (errors.length) {
          reject([{ errors, rule }]);
          return;
        }
      }
      resolve([]);
    });
  } else {
    const rulePromises = filledRules.map(
      (rule) => validateRule(name, value, rule, options, messageVariables).then((errors) => ({ errors, rule }))
    );
    summaryPromise = (validateFirst ? finishOnFirstFailed(rulePromises) : finishOnAllFailed(rulePromises)).then((errors) => {
      return Promise.reject(errors);
    });
  }
  summaryPromise.catch((e) => e);
  return summaryPromise;
}
async function finishOnAllFailed(rulePromises) {
  return Promise.all(rulePromises).then(
    (errorsList) => {
      const errors = [].concat(...errorsList);
      return errors;
    }
  );
}
async function finishOnFirstFailed(rulePromises) {
  let count = 0;
  return new Promise((resolve) => {
    rulePromises.forEach((promise) => {
      promise.then((ruleError) => {
        if (ruleError.errors.length)
          resolve([ruleError]);
        count += 1;
        if (count === rulePromises.length)
          resolve([]);
      });
    });
  });
}

exports.validateRules = validateRules;
//# sourceMappingURL=validateUtil.cjs.map
