#!/usr/bin/env node

// First configure the logger, so it does not spam the console
const logger = require('../lib/logger')
logger.transports.forEach((transport) => transport.level = 'warning')

const models = require('../lib/models/')
const readline = require('readline-sync')
const minimist = require('minimist')

function showUsage (tips) {
  console.log(`${tips}

Command-line utility to create users for email-signin.

Usage: bin/manage_users [--pass password] (--add | --del) user-email
	Options:
		--add 	Add user with the specified user-email
		--del 	Delete user with specified user-email
		--reset Reset user password with specified user-email
		--pass	Use password from cmdline rather than prompting
`)
  process.exit(1)
}

function getPass (argv, action) {
  // Find whether we use cmdline or prompt password
  if (typeof argv['pass'] !== 'string') {
    return readline.question(`Password for ${argv[action]}:`, { hideEchoBack: true })
  }
  console.log('Using password from commandline...')
  return argv['pass']
}

// Using an async function to be able to use await inside
async function createUser (argv) {
  const existing_user = await models.User.findOne({ where: { email: argv['add'] } })
  // Cannot create already-existing users
  if (existing_user) {
    console.log(`User with e-mail ${existing_user.email} already exists! Aborting ...`)
    process.exit(2)
  }

  const pass = getPass(argv, 'add')
  if (pass.length === 0) {
    console.log('Password cannot be empty!')
    process.exit(1)
  }

  // Lets try to create, and check success
  const ref = await models.User.create({ email: argv['add'], password: pass })
  if (ref === undefined) {
    console.log(`Could not create user with email ${argv['add']}`)
    process.exit(1)
  } else {
    console.log(`Created user with email ${argv['add']}`)
  }
}

// Using an async function to be able to use await inside
async function deleteUser (argv) {
  // Cannot delete non-existing users
  const existing_user = await models.User.findOne({ where: { email: argv['del'] } })
  if (!existing_user) {
    console.log(`User with e-mail ${argv['del']} does not exist, cannot delete`)
    process.exit(1)
  }

  // Sadly .destroy() does not return any success value with all
  // backends. See sequelize #4124
  await existing_user.destroy()
  console.log(`Deleted user ${argv['del']} ...`)
}

// Using an async function to be able to use await inside
async function resetUser (argv) {
  const existing_user = await models.User.findOne({ where: { email: argv['reset'] } })
  // Cannot reset non-existing users
  if (!existing_user) {
    console.log(`User with e-mail ${argv['reset']} does not exist, cannot reset`)
    process.exit(1)
  }

  // set password and save
  existing_user.password = getPass(argv, 'reset')
  await existing_user.save()
  console.log(`User with email ${argv['reset']} password has been reset`)
}

const options = {
  add: createUser,
  del: deleteUser,
  reset: resetUser,
}

// Perform commandline-parsing and always treat 'pass' argument as string
const argv = minimist(process.argv.slice(2), { string: ['pass'] })

const keys = Object.keys(options)
const opts = keys.filter((key) => argv[key] !== undefined)
const action = opts[0]

// Check for options missing
if (opts.length === 0) {
  showUsage(`You did not specify either ${keys.map((key) => `--${key}`).join(' or ')}!`)
}

// Check if both are specified
if (opts.length > 1) {
  showUsage(`You cannot ${action.join(' and ')} at the same time!`)
}
// Check if not string
if (typeof argv[action] !== 'string') {
  showUsage(`You must follow an email after --${action}`)
}

// Call respective processing functions
options[action](argv).then(function () {
  process.exit(0);
});
