'use strict';

var request = require('request'),
    jwt = require('jsonwebtoken');

/*
 auth0Namespace is yuor domain in Auth0, e.g. https://yourcompany.auth0.com
 clientId, identifies your app (mosca) with Auth0
 clientSecret, is used to sign the JWT (and validate it when using JWT mode)
 connection identifies the user store you want to use in Auth0. It must be one that supports the
 'Resource Owner' flow: Active Directory, database, etc.
 */

// Initialize with reference to auth0 domains
function Auth0Mosca(domains) {

    this.domains = domains;

    this.selectDomainAndUser = function (username) {

        var user,
            userStr = username.toString(),
            domain = userStr.split("/")[1];

        if (!domain) {
            domain = userStr.split("@")[1];
            user = userStr;
        } else {
            user = userStr.substr(0, userStr.length - domain.length - 1);
        }

        return {'user': user, 'domain': domain};

    };

    this.authenticateJWT = function (client, username, password, callback) {

        var domainUser, config;
        if (!username || !password) {
            return callback("Invalid Credentials", false);
        }

        domainUser = this.selectDomainAndUser(username);

        if (!domainUser.user || !domainUser.domain || domainUser.user !== 'JWT') {
            return callback("Invalid Credentials", false);
        }

        config = this.domains[domainUser.domain];

        if (!config) {
            return callback("Invalid Credentials", false);
        }

        jwt.verify(password, new Buffer(config.clientSecret, 'base64'), function (err, profile) {
            if (err) {
                return callback("Error getting UserInfo", false);
            }
            client.domain = profile.domain;
            client.deviceProfile = profile;
            return callback(null, true);
        });
    };

    this.authenticateCredentials = function (client, username, password, callback) {
        var domainUser, config, data;

        if (!username || !password) {
            return callback("Invalid Credentials", false);
        }

        domainUser = this.selectDomainAndUser(username);

        if (!domainUser.user || !domainUser.domain) {
            return callback("Invalid Credentials", false);
        }

        config = this.domains[domainUser.domain];

        if (!config) {
            return callback("Invalid Credentials", false);
        }

        data = {
            client_id: config.clientId, // {client-name}
            username: domainUser.user,
            password: password.toString(),
            connection: 'Username-Password-Authentication',
            grant_type: "password",
            scope: 'openid profile'
        };

        request.post({
            headers: {
                "Content-type": "application/json"
            },
            url: config.endpoint + '/oauth/ro',
            body: JSON.stringify(data)
        }, function (e, r, b) {

            if (e) {
                return callback(e, false);
            }
            r = JSON.parse(b);

            if (r.error) {
                return callback(r, false);
            }

            jwt.verify(r.id_token, new Buffer(config.clientSecret, 'base64'), function (err, profile) {

                if (err) {
                    return callback("Error getting UserInfo", false);
                }
                client.domain = profile.domain;
                client.deviceProfile = profile; //profile attached to the client object
                return callback(null, true);
            });
        });
    };
}

/*
 Used when the device is sending JWT instead of credentials.
 mqtt.username must be JWT
 mqtt.password is the JWT itself
 */
Auth0Mosca.prototype.authenticateWithJWT = function () {

    var self = this;

    return function (client, username, password, callback) {

        self.authenticateJWT(client, username, password, callback);
    };
};

/*
 Used when the device is sending credentials.
 mqtt.username must correspond to the device username in the Auth0 connection
 mqtt.password must correspond to the device password
 */
Auth0Mosca.prototype.authenticateWithCredentials = function () {

    var self = this;

    return function (client, username, password, callback) {

        self.authenticateCredentials(client, username, password, callback);
    };
};

/*
 Used when the device may send username/password or JWT credentials.
 mqtt.username must correspond to the device username in the Auth0 connection
 mqtt.password must correspond to the device password
 First JWT token is checked and if it fails username/password credentials is verified
 */
Auth0Mosca.prototype.authenticate = function () {

    var self = this;

    return function (client, username, password, callback) {

        if (!username) {
            return callback("Missing username", false);
        }

        var domainUser = self.selectDomainAndUser(username);

        self.authenticateJWT(client, username, password, function (err, verdict) {
            if (err) {
                if (domainUser.user !== 'JWT') {
                    self.authenticateCredentials(client, username, password, function (err, verdict) {
                        if (err) {
                            return callback(err, false);
                        }
                        return callback(null, true);
                    });
                } else {
                    return callback(null, false);
                }
            } else {
                return callback(null, true);
            }
        });
    };
};

Auth0Mosca.prototype.authorizePublish = function () {
    return function (client, topic, payload, callback) {
        // callback(null, client.deviceProfile && client.deviceProfile.topics && client.deviceProfile.topics.indexOf(topic) > -1);
        callback(null, true);
    };
};

Auth0Mosca.prototype.authorizeSubscribe = function () {
    return function (client, topic, callback) {
        // callback(null, client.deviceProfile && client.deviceProfile.topics && client.deviceProfile.topics.indexOf(topic) > -1);
        callback(null, true);
    };
};

module.exports = Auth0Mosca;
@@ -616,22 +616,39 @@
     var 
+JWT,%0A            
 user,%0A
-
         
@@ -742,32 +742,73 @@
  if (!domain) %7B%0A
+            JWT = userStr.split(%22@%22)%5B0%5D;%0A
             doma
@@ -835,16 +835,119 @@
 @%22)%5B1%5D;%0A
+            if (JWT === 'JWT' %7C%7C JWT === 'jwt') %7B%0A                user = JWT;%0A            %7D else %7B%0A    
         
@@ -966,16 +966,30 @@
 serStr;%0A
+            %7D%0A
         
@@ -1074,32 +1074,32 @@
  1);%0A        %7D%0A%0A
+
         return %7B
@@ -1131,17 +1131,16 @@
 omain%7D;%0A
-%0A
     %7D;%0A%0A

Handle token login with domain