const AuthTokens = require('../authtokens');
const bcrypt = require('bcrypt');


class User
{
  constructor(values)
  {
    var self = this;

    self.id = values.id || values._id || null;
    self.username = values.username || null;
    self.password = values.password || null;
    self.email = values.email || null;
    self.auth = values.auth || [];

    if (values.hasOwnProperty('active'))
      self.active = (values.active === true);
    else
      self.active = true;

    self.created = values.created || new Date();
    self.createdByUserId =  values.createdByUserId || null;
  }

  hasAuth(token)
  {
    return self.auth.includes(token);
  }
}


class UserRepository
{
  constructor(store)
  {
    var self = this;
    self.store = store;
  }


  init()
  {
    var self = this;

    return new Promise((resolve, reject) =>
    {
      // Initialize database if empty
      self.store.count({}, (err, count) =>
      {
        if (err)
        {
          reject(err);
          return;
        }

        if (count == 0)
        {
          self.addUser(new User({
              username: 'admin',
              password: 'changeme',
              auth: AuthTokens.all
            }))
            .then(() => { resolve() })
            .catch((e) => { reject(e); });
        }
        else
          resolve();
      });
    });
  }


  getLoginUser(username, password)
  {
    var self = this;

    return new Promise((resolve, reject) =>
    {
      self.store.findOne({ username: username, active: true }, (err, doc) =>
      {
        if (err)
        {
          reject(err);
          return;
        }

        if (doc == null)
        {
          resolve(false);
          return;
        }

        bcrypt.compare(password, doc.hashedPassword, (err, res) =>
        {
          if (err)
            reject(err)
          else
            resolve(res ? new User(doc) : null);
        });
      });
    });
  }


  addUser(user)
  {
    var self = this;

    return new Promise((resolve, reject) =>
    {
      bcrypt.hash(user.password, 10, function(err, hash)
      {
        if (err)
        {
          reject(err);
          return;
        }

        self.store.insert({
          username: user.username,
          email: user.email,
          hashedPassword: hash,
          created: user.created,
          createdByUserId: user.createdByUserId,
          active: user.active,
          auth: user.auth
        }, (err, dbUser) =>
        {
          if (err)
          {
            reject(err);
            return;
          }

          resolve(dbUser._id);
        });
      });
    });
  }


  getUsernames()
  {
    var self = this;

    return new Promise((resolve, reject) =>
    {
      self.store.find({}, (err, docs) =>
      {
        if (err)
        {
          reject(err);
          return;
        }

        var usernames = {};
        docs.forEach((dbUser) =>
        {
          usernames[dbUser._id] = dbUser.username
        });

        resolve(usernames);
      });
    });
  }
}


module.exports = {
  User,
  UserRepository
}