var objectPath = require('object-path');
var randomstring = require('randomstring');
var Promise = require('bluebird');
var util = require('util');
var exceptions = require('./exceptions');
var fs = require('fs');
var ejs = require('ejs');

module.exports = identity_check;

var filePath = __dirname + '/../resources/email-template.ejs';
var email_template = fs.readFileSync(filePath, 'utf8');

// IdentityCheck class

function IdentityCheck(user_data_store, logger) {
  this._user_data_store = user_data_store;
  this._logger = logger;
}

IdentityCheck.prototype.issue_token = function(userid, content, logger) {
  var five_minutes = 4 * 60 * 1000;
  var token = randomstring.generate({ length: 64 });
  var that = this;

  this._logger.debug('identity_check: issue identity token %s for 5 minutes', token);
  return this._user_data_store.issue_identity_check_token(userid, token, content, five_minutes)
  .then(function() {
    return Promise.resolve(token);
  });
}

IdentityCheck.prototype.consume_token = function(token, logger) {
  this._logger.debug('identity_check: consume token %s', token);
  return this._user_data_store.consume_identity_check_token(token)
}


// The identity_check middleware that allows the user two perform a two step validation
// using the user email

function identity_check(app, endpoint, icheck_interface) {
  app.get(endpoint, identity_check_get(endpoint, icheck_interface)); 
  app.post(endpoint, identity_check_post(endpoint, icheck_interface)); 
}


function identity_check_get(endpoint, icheck_interface) {
  return function(req, res) {
    var logger = req.app.get('logger');
    var identity_token = objectPath.get(req, 'query.identity_token');
    logger.info('GET identity_check: identity token provided is %s', identity_token);

    if(!identity_token) {
      res.status(403);
      res.send();
      return;
    }
 
    var email_sender = req.app.get('email sender');
    var user_data_store = req.app.get('user data store');
    var identity_check = new IdentityCheck(user_data_store, logger);

    identity_check.consume_token(identity_token, logger)
    .then(function(content) {
      objectPath.set(req, 'session.auth_session.identity_check', {});
      req.session.auth_session.identity_check.challenge = icheck_interface.challenge;
      req.session.auth_session.identity_check.userid = content.userid;
      res.render(icheck_interface.render_template);
    }, function(err) {
      logger.error('GET identity_check: Error while consuming token %s', err);
      throw new exceptions.AccessDeniedError('Access denied');
    })
    .catch(exceptions.AccessDeniedError, function(err) {
      logger.error('GET identity_check: Access Denied %s', err);
      res.status(403);
      res.send();
    })
    .catch(function(err) {
      logger.error('GET identity_check: Internal error %s', err);
      res.status(500);
      res.send();
    });
  }
}


function identity_check_post(endpoint, icheck_interface) {
  return function(req, res) {
    var logger = req.app.get('logger');
    var notifier = req.app.get('notifier');
    var user_data_store = req.app.get('user data store');
    var identity_check = new IdentityCheck(user_data_store, logger);
    var identity;

    icheck_interface.pre_check_callback(req)
    .then(function(id) {
      identity = id;
      var email_address = objectPath.get(identity, 'email');
      var userid = objectPath.get(identity, 'userid');

      if(!(email_address && userid)) {
        throw new exceptions.IdentityError('Missing user id or email address');
      }

      return identity_check.issue_token(userid, undefined, logger);
    }, function(err) {
      throw new exceptions.AccessDeniedError();
    })
    .then(function(token) {
      var original_url = util.format('https://%s%s', req.headers.host, req.headers['x-original-uri']);
      var link_url = util.format('%s?identity_token=%s', original_url, token); 

      logger.info('POST identity_check: notify to %s', identity.userid);
      return notifier.notify(identity, icheck_interface.email_subject, link_url);
    })
    .then(function() {
      res.status(204);
      res.send();
    })
    .catch(exceptions.IdentityError, function(err) {
      logger.error('POST identity_check: IdentityError %s', err);
      res.status(400);
      res.send();
    })
    .catch(exceptions.AccessDeniedError, function(err) {
      logger.error('POST identity_check: AccessDeniedError %s', err);
      res.status(403);
      res.send();
    })
    .catch(function(err) {
      logger.error('POST identity_check: Error %s', err);
      res.status(500);
      res.send();
    });
  }
}