/* eslint-disable no-param-reassign */
import mapValues from 'lodash/mapValues';
import ValidationError from '../ValidationError';
import Ref from '../Reference';

const formatError = ValidationError.formatError;

function resolveParams(oldParams, newParams, resolve) {
  return mapValues({ ...oldParams, ...newParams }, resolve);
}

function createErrorFactory({ value, label, resolve, originalValue, ...opts }) {
  return function createError({
    path = opts.path,
    message = opts.message,
    type = opts.name,
    params,
  } = {}) {
    params = {
      path,
      value,
      originalValue,
      label,
      ...resolveParams(opts.params, params, resolve),
    };

    return Object.assign(
      new ValidationError(
        formatError(message, params)
        , value
        , path
        , type,
      )
      , { params });
  };
}

export default function createValidation(options) {
  const { name, message, test, params } = options;

  function validate({ value, path, label, options: validateOptions, originalValue, ...rest }) {
    const parent = validateOptions.parent;
    const resolve = val => (Ref.isRef(val) ? val.getValue(parent, validateOptions.context) : val);

    const createError = createErrorFactory({
      message,
      path,
      value,
      originalValue,
      params,
      label,
      resolve,
      name,
    });

    const ctx = {
      path,
      parent,
      type: name,
      createError,
      resolve,
      options: validateOptions,
      ...rest,
    };

    return Promise
      .resolve(test.call(ctx, value))
      .then((validOrError) => {
        if (ValidationError.isError(validOrError)) {
          throw validOrError;
        } else if (!validOrError) {
          throw createError();
        }
      });
  }

  validate.TEST_NAME = name;
  validate.TEST_FN = test;
  validate.TEST = options;

  return validate;
}

module.exports.createErrorFactory = createErrorFactory;

@@ -73,16 +73,49 @@
 Values';
+%0A%0Aimport Ref from '../Reference';
 %0Aimport 
@@ -160,40 +160,8 @@
 or';
-%0Aimport Ref from '../Reference';
 %0A%0Aco

Reorder imports