const crypto = require('crypto');

module.exports.generateFromContent = function generateFromContent(options) {
    options = options || {};

    const hash = crypto.createHash('sha256'),
        content = options.content;

    let text = '';

    hash.update(content);

    text += [content, hash.digest('base64')].join('|');
    return new Buffer(text).toString('base64');
};

module.exports.generateFromEmail = function generateFromEmail(options) {
    options = options || {};

    const hash = crypto.createHash('sha256'),
        expires = options.expires,
        email = options.email,
        secret = options.secret;

    let text = '';

    hash.update(String(expires));
    hash.update(email.toLocaleLowerCase());
    hash.update(String(secret));

    text += [expires, email, hash.digest('base64')].join('|');
    return new Buffer(text).toString('base64');
};

module.exports.resetToken = {
    generateHash: function generateHash(options) {
        options = options || {};

        var hash = crypto.createHash('sha256'),
            expires = options.expires,
            email = options.email,
            dbHash = options.dbHash,
            password = options.password,
            text = '';

        hash.update(String(expires));
        hash.update(email.toLocaleLowerCase());
        hash.update(password);
        hash.update(String(dbHash));

        text += [expires, email, hash.digest('base64')].join('|');
        return new Buffer(text).toString('base64');
    },
    extract: function extract(options) {
        options = options || {};

        var token = options.token,
            tokenText = new Buffer(token, 'base64').toString('ascii'),
            parts,
            expires,
            email;

        parts = tokenText.split('|');

        // Check if invalid structure
        if (!parts || parts.length !== 3) {
            return false;
        }

        expires = parseInt(parts[0], 10);
        email = parts[1];

        return {
            expires: expires,
            email: email
        };
    },
    compare: function compare(options) {
        options = options || {};

        var tokenToCompare = options.token,
            parts = exports.resetToken.extract({token: tokenToCompare}),
            dbHash = options.dbHash,
            password = options.password,
            generatedToken,
            diff = 0,
            i;

        if (isNaN(parts.expires)) {
            return false;
        }

        // Check if token is expired to prevent replay attacks
        if (parts.expires < Date.now()) {
            return false;
        }

        generatedToken = exports.resetToken.generateHash({
            email: parts.email,
            expires: parts.expires,
            dbHash: dbHash,
            password: password
        });

        if (tokenToCompare.length !== generatedToken.length) {
            diff = 1;
        }

        for (i = tokenToCompare.length - 1; i >= 0; i = i - 1) {
            diff |= tokenToCompare.charCodeAt(i) ^ generatedToken.charCodeAt(i);
        }

        return diff === 0;
    }
};
