const _ = require('lodash');


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

    self.id = values.id || values._id || null;
    self.userId = values.userId || null;
    self.created = values.created || new Date();
    self.expiration = values.expiration || null;
  }
}


class CodeRepository
{
  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('admin', null, 'test', null);

        resolve();
      });
    });
  }


  findCodeUserId(code)
  {
    var self = this;

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

        resolve(doc !== null ? doc.userId : null);
      });
    });
  }


  async addCode(userId, expiration)
  {
    var self = this;

    return await retry(async bail =>
    {
      var code = shortid.generate();

      if ((await self.findCodeUserId(code)) !== null)
        throw new Error('Code ' + code + ' already exists');

      self.store.insert({
        _id: code,
        userId: userId,
        created: new Date(),
        expiration: expiration
      })

      return code;
    }, {
      retries: 100,
      minTimeout: 0,
      maxTimeout: 0
    });
  }


  getCodes(userId)
  {
    var self = this;

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

        resolve(_.map(docs, (doc) => new Code(doc)));
      });
    });
  }
}


module.exports = {
  Code,
  CodeRepository
}