var _              = require('lodash'),
    errors         = require('../errors'),
    appBookshelf = require('./base'),
    Promise        = require('bluebird'),

    Role,
    Roles;
    
Role = appBookshelf.Model.extend({
  
  tableName: 'roles',
  
  users: function users() {
    return this.belongsToMany('User');
  },
  
  permissions: function permissions() {
    return this.belongsToMany('Permission');
  }
}, {
  /**
  * Returns an array of keys permitted in a method's `options` hash, depending on the current method.
  * @param {String} methodName The name of the method to check valid options for.
  * @return {Array} Keys allowed in the `options` hash of the model's method.
  */
  permittedOptions: function permittedOptions(methodName) {
    var options = appBookshelf.Model.permittedOptions(),
      
        // whitelists for the `options` hash argument on methods, by method name.
        // these are the only options that can be passed to Bookshelf / Knex.
        validOptions = {
          findOne: ['withRelated']
        };
        
    if (validOptions[methodName]) {
      options = options.concat(validOptions[methodName]);
    }
    
    return options;
  },
  
  permissible: function permissible(roleModelOrId, action, context, loadedPermissions, hasUserPermission, hasAppPermission) {
    var self = this,
        checkAgainst = [],
        origArgs;
    
    // If we passed in an id instead of a model, get the model
    // then check the permissions
    if (_.isNumber(roleModelOrId) || _.isString(roleModelOrId)) {
      // Grab the original args without the first one
      origArgs = _.toArray(arguments).slice(1);
      // Get the actual model
      return this.findOne({id: roleModelOrId, status: 'all'}).then(function then(foundRoleModel) {
        // Build up the original args but substitute with actual model
        var newArgs = [foundRoleModel].concat(origArgs);
        
        return self.permissible.apply(self, newArgs);
      }, errors.logAndThrowError);
    }
    
    if (action === 'assign' && loadedPermissions.user) {
      if (_.any(loadedPermissions.user.roles, {name: 'Owner'})) {
        checkAgainst = ['Owner', 'Administrator', 'Staff', 'Subscriber'];
      } else if (_.any(loadedPermissions.user.roles, {name: 'Administrator'})) {
        checkAgainst = ['Administrator', 'Staff', 'Subscriber'];
      } else if (_.any(loadedPermissions.user.roles, {name: 'Staff'})) {
        checkAgainst = ['Subscriber'];
      }
      
      // Role in the list of permissible roles
      hasUserPermission = roleModelOrId && _.contains(checkAgainst, roleModelOrId.get('name'));
    }
    
    if (hasUserPermission && hasAppPermission) {
      return Promise.resolve();
    }
    
    return Promise.reject();
  }
});

Roles = appBookshelf.Collection.extend({
  model: Role
});

module.exports = {
  Role: appBookshelf.model('Role', Role),
  Roles: appBookshelf.collection('Roles', Roles)
};