'use strict';

var Roles = function(roles, notLoggedInCallback, unauthorizedCallback){
    if(!roles) {
        throw new Error('Roles were not provided');
    }

    this.roles = {};
    for (let role of roles){
        var rolesSet ;
        if(role.inherit){
            if(typeof role.inherit == 'string') role.inherit = [role.inherit];
            rolesSet = role.inherit.map(roleName => this.roles[roleName]);
            rolesSet = [].concat.apply([], rolesSet);
            rolesSet = Array.from(new Set(rolesSet));
            rolesSet.push(role.name);
        }else{
            rolesSet = [role.name];
        }

        this.roles[role.name] = rolesSet;
    }


    this.hasRole = (role) => {
        return (req, res, next) => {
            if(!req.user) {
                (notLoggedInCallback && notLoggedInCallback(req, res)) || res.sendStatus(401);
                return;
            }

            if(!req.user.role){
                (unauthorizedCallback && unauthorizedCallback(req, res)) || res.sendStatus(401);
                return;
            }


            if(this.checkUserRole(req.user.role, role)){
                next();
            }else{
                (unauthorizedCallback && unauthorizedCallback(req, res)) || res.sendStatus(401);
            }
        }
    };

    this.checkUserRole = (userRole, checkRole) => {
        if(typeof checkRole == 'string') checkRole = [checkRole];
        return this.roles[userRole] && checkRole.filter(value => this.roles[userRole].indexOf(value) >= 0).length > 0;
    };

    this.middleware = () => {
        return (req, res, next) => {
            req.hasRole = (role) => {
                if(!req.user || !req.user.role) return false;
                return this.checkUserRole(req.user.role, role);
            };

            next();
        };
    }

};


module.exports = Roles;