/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
/* global require */
/* global CL */
/* global forge */

module.exports = (function() {

    'use strict';

    var Q = require('q');
    var config = require('../client/config.js');
    var XMLHttpRequest = XMLHttpRequest || require('xhr2');


    // derives a single value

    var derive = function(startVotingKey, salt) {
        var deriver = CL.primitives.service.getPbkdfSecretKeyGenerator();
        var hashedSalt = CL.primitives.service.getHash([forge.util.encode64(salt)]);
        var derived = deriver.generateSecret(forge.util.encode64(startVotingKey), hashedSalt);
        return forge.util.bytesToHex(forge.util.decode64(derived));
    };

    // derives { credentialId, pin }

    var deriveKey = function(startVotingKey, eeId) {
        return {
            credentialId: derive(startVotingKey, 'authid' + eeId),
            pin: derive(startVotingKey, 'authpassword' + eeId)
        };
    };

	var decipherAndResolveAuthKey = function(deferred, authResponse, pin) {

        try {

            var encodedSVK = CL.symmetric.service.decrypt(
                forge.util.encode64(forge.util.hexToBytes(pin)),
                authResponse.encryptedSVK
            );
            var svk = forge.util.decode64(encodedSVK);
            deferred.resolve(svk);

        } catch (e) {
            deferred.reject('Could not decipher SVK');
        }

    };
	
    // retrieves a SVK from an authentication string and (optional) challenge

    var authenticate = function(authenticationString, challenge, tenantId, eeId) {

        var deferred = Q.defer();

        var authObject = deriveKey(authenticationString, eeId);

        // request extended auth endpoint

        var endpoint = config('host') + config('endpoints.authentication')
            .replace('{tenantId}', tenantId)
            .replace('{electionEventId}', eeId);

        var xhr = new XMLHttpRequest();
        xhr.open('POST', endpoint);
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status === 200) {

                    // check response. if 'numberOfRemainingAttempts', treat it as an error

                    var response = null;
                    try {
                        response = JSON.parse(this.responseText);
                        if (response.numberOfRemainingAttempts) {
                            deferred.reject(response);
                            return;
                        }
                    } catch (e) {
                        deferred.reject({
                            unparseable: this.responseText
                        });
                        return;
                    }

                    decipherAndResolveAuthKey(deferred, response, authObject.pin);

                } else {
                    deferred.reject(xhr.status);
                }
            }
        };
        xhr.onerror = function(error) {
            try {
                console.log('** xhr.error', error);
                deferred.reject(xhr.status);
            } catch (e) {
				//This block is intentionally left blank
			}
        };
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.send(JSON.stringify({
            authId: authObject.credentialId,
            extraParam: challenge
        }));

        return deferred.promise;

    };

    return {
        authenticate: authenticate,
        deriveKey: deriveKey
    };

})();
