const _ = require('lodash');

const PRODUCTION_ENVIRONMENTS = [
    'production', 'corp', 'prestable', 'corp-prestable'
];

const STRINGIFIED_FIELDS = [
    'body', 'options.body', 'err'
];

const SENSITIVE_FIELDS = [
    'Authorization',
    'X-Ya-User-Ticket',
    'X-Ya-Service-Ticket',
    '_request.options.headers.Cookie',
    '_request.options.headers.cookie',
    '_request.options.headers.Authorization',
    '_request.options.headers.X-Ya-User-Ticket',
    '_request.options.headers.X-Ya-Service-Ticket',
    'sessionid',
    'sslsessionid',
    '_request.url.query.sessionid',
    '_request.url.query.sslsessionid',
    '_request.url.query.password',
    'tvm_ticket',
    '_response.blackbox.ticket',
    '_response.admin-api.ticket',
    '_response.gendarme.ticket',
    '_response.tvm_tickets.blackbox',
    '_response.tvm_tickets.directory_admin',
    '_response.tvm_tickets.dns',
    '_response.tvm_tickets.isearch',
    '_response.tvm_tickets.gendarme',
    '_response.user_ticket',
    '_response.session.user_ticket',
    '_response.password',
    '_response.body.password',
    '_request.options.body.password'
];

function maskSensitive(data) {
    if (typeof data === 'string')
        return maskString(data);
    else if (data && typeof data === 'object')
        return maskObject(data);
    return data;
}

function maskObject(data) {
    let parsedFields = [];

    STRINGIFIED_FIELDS.forEach(key => {
        let value = _.get(data, key);
        if (typeof value === 'string') {
            try {
                _.set(data, key, JSON.parse(value));
                parsedFields.push(key);
            }
            catch(e) {}
        }
    });

    SENSITIVE_FIELDS.forEach(key => {
        let value = _.get(data, key);
        if (value !== undefined)
            _.set(data, key, getMaskedValue(value));
    });

    parsedFields.forEach(key => {
        let value = _.get(data, key);
        if (value !== undefined)
            _.set(data, key, JSON.stringify(value));
    });

    return data;
}

function maskString(data) {
    try {
        let parsedObject = JSON.parse(data);
        return maskObject(parsedObject);
    }
    catch(e) {}

    SENSITIVE_FIELDS.forEach(key => {
        let escapedKey = escapeRegExpPattern(key);
        let patterns = [
            new RegExp(`(\\b${escapedKey}:")([^"]+)(")`, 'g'),
            new RegExp(`(\\b${escapedKey}:\s+)([^\s]+)()`, 'g'),
            new RegExp(`(\\b${escapedKey}=)([^#&]+)()`, 'g'),
            new RegExp(`(\\b${escapedKey}\s+=\s+)([^\s]+)`, 'g')
        ];

        patterns.forEach(pattern => {
            data = data.replace(pattern, '$1***$3');
        });
    });

    return data;
}

function escapeRegExpPattern(text) {
    return text.replace(/([\.\?\*\+\[\]\{\}\(\)\^\$])/g, '\\$1');
}

function getMaskedValue(value) {
    let isPartlyExposable = (
        process.env.NODE_ENV &&
        PRODUCTION_ENVIRONMENTS.indexOf(process.env.NODE_ENV) === -1 &&
        typeof value === 'string' &&
        value.length > 50
    );
    return isPartlyExposable ? (value.substring(0, 32) + '***') : '***';
}

module.exports = maskSensitive;
