import Users from '../modules/index.js';
import {
  runCallbacks,
  runCallbacksAsync,
  Utils,
  debug,
  debugGroup,
  debugGroupEnd,
} from 'meteor/vulcan:lib'; // import from vulcan:lib because vulcan:core isn't loaded yet
import clone from 'lodash/clone';

// TODO: the following should use async/await, but async/await doesn't seem to work with Accounts.onCreateUser
function onCreateUserCallback(options, user) {
  debug('');
  debugGroup('--------------- start \x1b[35m onCreateUser ---------------');
  debug(`Options: ${JSON.stringify(options)}`);
  debug(`User: ${JSON.stringify(user)}`);

  const schema = Users.simpleSchema()._schema;

  delete options.password; // we don't need to store the password digest
  delete options.username; // username is already in user object

  options = runCallbacks({ name: 'user.create.validate.before', iterator: options });
  // OpenCRUD backwards compatibility
  options = runCallbacks('users.new.validate.before', options);

  // validate options since they can't be trusted
  // omit username since we deleted it above
  Users.simpleSchema().omit('username').validate(options);

  // check that the current user has permission to insert each option field
  _.keys(options).forEach(fieldName => {
    var field = schema[fieldName];
    if (!field || !Users.canCreateField(user, field)) {
      throw new Error(
        Utils.encodeIntlError({ id: 'app.disallowed_property_detected', value: fieldName })
      );
    }
  });

  // extend user with options
  user = Object.assign(user, options);

  // run validation callbacks
  user = runCallbacks({ name: 'user.create.validate', iterator: user, properties: {} });
  // OpenCRUD backwards compatibility
  user = runCallbacks('users.new.validate', user);

  // run onCreate step
  for (let fieldName of Object.keys(schema)) {
    let autoValue;
    if (schema[fieldName].onCreate) {
      const document = clone(user);
      // eslint-disable-next-line no-await-in-loop
      autoValue = schema[fieldName].onCreate({ document });
    } else if (schema[fieldName].onInsert) {
      // OpenCRUD backwards compatibility
      // eslint-disable-next-line no-await-in-loop
      autoValue = schema[fieldName].onInsert(clone(user));
    }
    if (typeof autoValue !== 'undefined') {
      user[fieldName] = autoValue;
    }
  }
  user = runCallbacks({ name: 'user.create.before', iterator: user, properties: {} });
  user = runCallbacks('users.new.sync', user);

  runCallbacksAsync({ name: 'user.create.async', properties: { data: user, document: user, user, collection: Users } });
  // OpenCRUD backwards compatibility
  runCallbacksAsync('users.new.async', user);

  // check if all required fields have been filled in. If so, run profile completion callbacks
  if (Users.hasCompletedProfile(user)) {
    runCallbacksAsync('user.profileCompleted.async', user);
    // OpenCRUD backwards compatibility
    runCallbacksAsync('users.profileCompleted.async', user);
  }

  debug(`Modified User: ${JSON.stringify(user)}`);
  debugGroupEnd();
  debug('--------------- end \x1b[35m onCreateUser ---------------');
  debug('');

  return user;
}

Meteor.startup(() => {
  if (typeof Accounts !== 'undefined') {
    Accounts.onCreateUser(onCreateUserCallback);
  }
});

@@ -42,18 +42,16 @@
 import %7B
-%0A 
  runCall
@@ -56,18 +56,16 @@
 llbacks,
-%0A 
  runCall
@@ -79,28 +79,22 @@
 ync,
-%0A 
  Utils,
-%0A 
  debug,
-%0A 
  deb
@@ -101,18 +101,16 @@
 ugGroup,
-%0A 
  debugGr
@@ -116,17 +116,28 @@
 roupEnd,
-%0A
+ throwError 
 %7D from '
@@ -252,16 +252,46 @@
 /clone';
+%0Aimport get from 'lodash/get';
 %0A%0A// TOD
@@ -395,16 +395,22 @@
 ateUser%0A
+async 
 function
@@ -629,16 +629,95 @@
 r)%7D%60);%0A%0A
+  const properties = %7B data: user, document: user, user, collection: Users %7D;%0A%0A
   const 
@@ -1201,16 +1201,21 @@
 Schema()
+%0A    
 .omit('u
@@ -1223,16 +1223,21 @@
 ername')
+%0A    
 .validat
@@ -1483,17 +1483,8 @@
 ror(
-%0A        
 Util
@@ -1562,23 +1562,16 @@
 dName %7D)
-%0A      
 );%0A    %7D
@@ -1644,24 +1644,488 @@
  options);%0A%0A
+  let validationErrors = %5B%5D;%0A  // new callback API (Oct 2019)%0A  validationErrors = await runCallbacks(%7B%0A    name: 'user.create.validate',%0A    callbacks: get(Users, 'options.callbacks.create.validate', %5B%5D),%0A    iterator: validationErrors,%0A    properties,%0A  %7D);%0A  if (validationErrors.length) %7B%0A    console.log(validationErrors); // eslint-disable-line no-console%0A    throwError(%7B id: 'app.validation_error', data: %7B break: true, errors: validationErrors %7D %7D);%0A  %7D%0A%0A
   // run val
@@ -2886,16 +2886,219 @@
    %7D%0A  %7D
+%0A%0A  // new callback API (Oct 2019)%0A  user = await runCallbacks(%7B%0A    name: 'user.create.before',%0A    callbacks: get(Users, 'options.callbacks.create.after', %5B%5D),%0A    iterator: user,%0A    properties,%0A  %7D);
 %0A  user 
@@ -3227,16 +3227,55 @@
 er);%0A%0A  
+// new callback API (Oct 2019)%0A  await 
 runCallb
@@ -3285,16 +3285,20 @@
 sAsync(%7B
+%0A   
  name: '
@@ -3320,76 +3320,156 @@
 nc',
- properties: %7B data: user, document
+%0A    callbacks: get(Users, 'options.callbacks.create.async', %5B%5D),%0A    properties,%0A  %7D);%0A%0A  runCallbacksAsync(%7B name
 : 
+'
 user
-, user, collection: Users %7D
+.create.async', properties
  %7D);

Add missing user creation callbacks