
import feathersErrors from 'feathers-errors';

import getItems from './get-items';

const errors = feathersErrors.errors;

export default function (schema, ajvOrAjv, options = { allErrors: true }) {
  const addNewError = options.addNewError || addNewErrorDflt;
  delete options.addNewError;
  // TODO: Any better way to tell if ajvOrAjv is an instance or a constructor?
  let ajv, Ajv;
  if (typeof ajvOrAjv.addKeyword !== 'function') {
    Ajv = ajvOrAjv;
    ajv = new Ajv(options);
  } else {
    ajv = ajvOrAjv;
  }
  const validate = ajv.compile(schema); // for fastest execution

  return hook => {
    const items = getItems(hook);
    const itemsArray = Array.isArray(items) ? items : [items];
    const itemsLen = itemsArray.length;
    let errorMessages = null;
    let invalid = false;

    return Promise.all(itemsArray.map((item, index) => {
      return Promise.resolve(validate(item))
        // Handler for synchronous validation
        .then((isValid) => {
          if (!isValid) {
            return Promise.reject(
              new ajv.constructor.ValidationError(validate.errors));
          }
        })
        .catch((err) => {
          if (!(err instanceof ajv.constructor.ValidationError)) throw err;

          invalid = true;

          err.errors.forEach(ajvError => {
            errorMessages = addNewError(errorMessages, ajvError, itemsLen, index);
          });
        });
    })).then(() => {
      if (invalid) {
        throw new errors.BadRequest('Invalid schema', { errors: errorMessages });
      }
    });
  };
}

function addNewErrorDflt (errorMessages, ajvError, itemsLen, index) {
  const leader = itemsLen === 1 ? '' : `in row ${index + 1} of ${itemsLen}, `;
  let message;

  if (ajvError.dataPath) {
    message = `'${leader}${ajvError.dataPath.substring(1)}' ${ajvError.message}`;
  } else {
    message = `${leader}${ajvError.message}`;
    if (ajvError.params && ajvError.params.additionalProperty) {
      message += `: '${ajvError.params.additionalProperty}'`;
    }
  }

  return (errorMessages || []).concat(message);
}

@@ -815,24 +815,52 @@
 = false;%0D%0A%0D%0A
+    if (schema.$async) %7B%0D%0A  
     return P
@@ -915,31 +915,17 @@
     
+  
 return 
-Promise.resolve(
 vali
@@ -934,17 +934,16 @@
 te(item)
-)
 %0D%0A      
@@ -948,75 +948,137 @@
     
-// Handler for synchronous validation%0D%0A        .then((isV
+  .catch(err =%3E %7B%0D%0A            if (!(err instanceof ajv.constructor.ValidationError)) throw err;%0D%0A%0D%0A            inv
 alid
-)
  =
-%3E %7B
+ true;%0D%0A
 %0D%0A  
@@ -1089,127 +1089,185 @@
     
-if (!isValid) %7B%0D%0A            return Promise.reject(%0D%0A              new ajv.constructor.ValidationError(validate.errors)
+  addErrors(err.errors, index);%0D%0A          %7D);%0D%0A      %7D)).then(() =%3E %7B%0D%0A        if (invalid) %7B%0D%0A          throw new errors.BadRequest('Invalid schema', %7B errors: errorMessages %7D
 );%0D%0A
@@ -1278,23 +1278,19 @@
     
- 
- 
 %7D%0D%0A
-  
       %7D)
 %0D%0A  
@@ -1289,29 +1289,55 @@
   %7D)
+;
 %0D%0A    
-    .catch((err
+%7D%0D%0A%0D%0A    itemsArray.forEach((item, index
 ) =%3E
@@ -1350,290 +1350,122 @@
     
-  
-  
 if (!
-(err instanceof ajv.constructor.ValidationError)) throw err;%0D%0A%0D%0A          invalid = true;%0D%0A%0D%0A          err.errors.forEach(ajvError =%3E %7B%0D%0A            errorMessages = addNewError(errorMessages, ajvError, itemsLen, index);%0D%0A          %7D);%0D%0A        %7D);%0D%0A    %7D)).then(() =%3E %7B%0D%0A  
+validate(item)) %7B%0D%0A        invalid = true;%0D%0A%0D%0A        addErrors(validate.errors, index);%0D%0A      %7D%0D%0A    %7D);%0A%0D%0A
     
@@ -1476,26 +1476,24 @@
 invalid) %7B%0D%0A
-  
       throw 
@@ -1569,22 +1569,189 @@
     
-  %7D
+%7D%0D%0A%0D%0A    function addErrors (errors, index) %7B%0D%0A      errors.forEach(ajvError =%3E %7B%0D%0A        errorMessages = addNewError(errorMessages, ajvError, itemsLen, index);
 %0D%0A    
+ 
+ 
 %7D);%0D%0A
+    %7D%0D%0A
   %7D;

Change async schemas validation Return Promise only if schema contains $async prop