import { Meteor } from 'meteor/meteor'
import { Accounts } from 'meteor/accounts-base'
import { check, Match } from 'meteor/check'
import { NotSignedInError } from '../errors/NotSignedInError'
import { PermissionDeniedError } from '../errors/PermissionDeniedError'

/** @module accounts/methods */

/**
 * Registers a new user by email+password and minimal profile fields.
 *
 * @methodOf {accounts/methods}
 * @function
 * @example
 * registerNewUser({
 *   email: janedow@example.com,
 *   password: 'mysupersecretpw',
 *   firstName: 'Jane',
 *   lastName: 'Doe',
 *   loginImmediately: true
 * })
 *
 *
 * @param options {object}
 * @param options.email {string}
 * @param options.password {string}
 * @param options.firstName {string}
 * @param options.lastName {string}
 * @param options.loginImmediately {boolean} if true performs a login after account creation
 * @return {Object<{ id: string, token: string=, tokenExpires: Date= }>} object with at least the _id of the created user and
 *   optionally the token and tokenExpires values when user is logged in immediately
 */
export const registerNewUser = function (options) {
  check(options, Match.ObjectIncluding({
    email: String,
    password: String,
    firstName: String,
    lastName: String,
    loginImmediately: Match.Maybe(Boolean)
  }))

  const { email, password, firstName, lastName, loginImmediately } = options

  if (Accounts.findUserByEmail(email)) {
    throw new PermissionDeniedError('accounts.userExists', { email })
  }

  const userId = Accounts.createUser({ email, password })

  // we add the firstName and lastName as toplevel fields
  // which allows for better handling in publications
  Meteor.users.update(userId, { $set: { firstName, lastName } })

  // let them verify their new account, so
  // they can use the full app functionality
  Accounts.sendVerificationEmail(userId, email)

  if (loginImmediately) {
    // signature: { id, token, tokenExpires }
    return Accounts._loginUser(this, userId)
  }

  // keep the same return signature here to let clients
  // better handle the response
  return { id: userId, token: undefined, tokenExpires: undefined }
}

/**
 * Updates the user profile fields
 *
 * @methodOf {accounts/methods}
 * @function
 * @example
 * updateUserProfile({ firstName: 'Jane', lastName: 'Doe' })
 *
 * @param firstName {string=}
 * @param lastName {string=}
 * @return {boolean} true if updated, otherwise false
 */
export const updateUserProfile = function ({ firstName, lastName }) {
  check(firstName, Match.Maybe(String))
  check(lastName, Match.Maybe(String))

  // in a meteor Method we can access the current user
  // via this.userId which is only present when an
  // authenticated user calls a Method
  const { userId } = this

  if (!userId) {
    throw new NotSignedInError({ userId })
  }

  const updateDoc = { $set: {} }

  if (firstName) {
    updateDoc.$set.firstName = firstName
  }

  if (lastName) {
    updateDoc.$set.lastName = lastName
  }

  return !!Meteor.users.update(userId, updateDoc)
}

/**
 * Deletes the current user. Works only for the user who invoked this method!
 *
 * @methodOf {accounts/methods}
 * @function
 * @example
 * deleteAccount()
 *
 * @return {boolean} true if removed else false
 */
export const deleteAccount = function () {
  const { userId } = this

  if (!userId) {
    throw new NotSignedInError({ userId })
  }

  return !!Meteor.users.remove(userId)
}
