const JWT = require('jsonwebtoken');
const KEY = 'Th1s is THE s3cr3t kEy. It secures the t0ken!';

const Token = {
  create: (payload, expires = '1h', callback) => {
    JWT.sign(payload, KEY, { expiresIn: expires }, callback);
  },
  verify: (token, callback) => {
    JWT.verify(token, KEY, callback);
  }
};

function createAnonymousToken (e) {
  Token.create({ username: null, can: ['view'] }, (err, token) => {
    if (err) {
      e.emit('token:create', err, null);
    }
    
    if (token) {
      e.emit('token:create', null, token);
    }
  });
}

function createAuthenticatedToken (e, user, expires = '1h', event = 'token:create') {
  Token.create({ username: user.name, can: user.can }, expires, (err, token) => {
    if (err) {
      e.emit(event, err, null);
    }
    
    if (token) {
      e.emit(event, null, token);
    }
  });
}

function refreshToken (e, token) {
  Token.verify(e, token, (err, decoded) => {
    if (err) {
      e.emit('token:refresh', err, null);
    }
    
    if (decoded) {
      createAuthenticatedToken(
        e,
        { username: decoded.username, can: decoded.can },
        'token:refresh'
      );
    }
  });
}

function validateToken (e, token, callback) {
  if (token) {
    token = token.replace(/(bearer|basic)\s/i, '');
  
    Token.verify(token, (err, decoded) => {
      var result = { valid: !!decoded, data: decoded };
    
      if (e) {
        if (err || !result.valid) {
          e.emit('token:validate', (err || result), null);
        }
      
        e.emit('token:validate', null, result);
      }
    
      else if (typeof callback === 'function') {
        if (err) {
          callback(err, null);
        }
      
        callback(null, result);
      }
    });
  } else {
    if (e) {
      e.emit('token:validate', 'No session token passed.', null);
    }

    else if (typeof callback === 'function') {
      callback('No session token passed.', null);
    }
  }
}

function verifyTokenThen (token, action, callback) {
  if (action === 'view') {
    callback(null, { hasPermission: true });
  } else {
    validateToken(null, token, (err, decoded) => {
      if (err) {
        callback('Session could not be validated.', null);
      }

      if (decoded) {
        callback(null, { hasPermission: (decoded.valid && (decoded.can.indexOf(action) > -1)) });
      }
    });
  }
}


module.exports = {
  anonymous: createAnonymousToken,
	create: createAuthenticatedToken,
	refresh: refreshToken,
	validate: validateToken,
	verifyThen: verifyTokenThen
};
