var AzureVM = {
    params: {},
    token: null,

    setParams: function (params) {
        ['app_id', 'password', 'tenant_id', 'subscription_id', 'resource_id'].forEach(function (field) {
            if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') {
                throw 'Required param is not set: ' + field + '.';
            }
        });

        AzureVM.params = params;
    },


    request: function (url, data) {
        if (typeof data === 'undefined' || data === null) {
            data = '';
        }

        var response, request = new HttpRequest();
            if (AzureVM.token) {
                request.addHeader('Accept: application/json');
                request.addHeader('Authorization: Bearer ' + AzureVM.token);
            }
    
        Zabbix.log(4, '[ Azure ] Sending request: ' + url);

        if (data !== '') {
            request.addHeader('Content-Type: application/x-www-form-urlencoded');
            response = request.post(url, data);
        }
        else {
            response = request.get(url);
        }

        Zabbix.log(4, '[ Azure ] Received response with status code ' + request.getStatus() + ': ' + response);

        if (request.getStatus() !== 200 || response === null) {
            throw 'Request failed with status code ' + request.getStatus() + ': ' + response;
        }

        try {
            return JSON.parse(response);
        }
        catch (error) {
            throw 'Failed to parse response received from API.';
        }
}

};

var metrics = [
    'Percentage CPU',
    'Network In',
    'Network Out',
    'Disk Read Bytes',
    'Disk Write Bytes',
    'Disk Read Operations/Sec',
    'Disk Write Operations/Sec',
    'CPU Credits Remaining',
    'CPU Credits Consumed',
    'Data Disk Read Bytes/sec',
    'Data Disk Write Bytes/sec',
    'Data Disk Read Operations/Sec',
    'Data Disk Write Operations/Sec',
    'Data Disk Queue Depth',
    'Data Disk Bandwidth Consumed Percentage',
    'Data Disk IOPS Consumed Percentage',
    'Data Disk Target Bandwidth',
    'Data Disk Target IOPS',
    'Data Disk Max Burst Bandwidth',
    'Data Disk Max Burst IOPS',
    'Data Disk Used Burst BPS Credits Percentage',
    'Data Disk Used Burst IO Credits Percentage',
    'OS Disk Read Bytes/sec',
    'OS Disk Write Bytes/sec',
    'OS Disk Read Operations/Sec',
    'OS Disk Write Operations/Sec',
    'OS Disk Queue Depth',
    'OS Disk Bandwidth Consumed Percentage',
    'OS Disk IOPS Consumed Percentage',
    'OS Disk Target Bandwidth',
    'OS Disk Target IOPS',
    'OS Disk Max Burst Bandwidth',
    'OS Disk Max Burst IOPS',
    'OS Disk Used Burst BPS Credits Percentage',
    'OS Disk Used Burst IO Credits Percentage',
    'Inbound Flows',
    'Outbound Flows',
    'Inbound Flows Maximum Creation Rate',
    'Outbound Flows Maximum Creation Rate',
    'Premium Data Disk Cache Read Hit',
    'Premium Data Disk Cache Read Miss',
    'Premium OS Disk Cache Read Hit',
    'Premium OS Disk Cache Read Miss',
    'VM Cached Bandwidth Consumed Percentage',
    'VM Cached IOPS Consumed Percentage',
    'VM Uncached Bandwidth Consumed Percentage',
    'VM Uncached IOPS Consumed Percentage',
    'Network In Total',
    'Network Out Total',
    'Available Memory Bytes'
],
    prepared_metrics = [],
    data = {};
    data['errors'] = {};
    data['metrics'] = {};

try {
    AzureVM.setParams(JSON.parse(value));

    try {
        result = AzureVM.request(
                'https://login.microsoftonline.com/' + encodeURIComponent(AzureVM.params.tenant_id) +'/oauth2/token',
                'grant_type=client_credentials&resource=' + encodeURIComponent('https://management.azure.com/') + '&client_id=' + encodeURIComponent(AzureVM.params.app_id) + '&client_secret=' + encodeURIComponent(AzureVM.params.password)
        );

        if ('access_token' in result) {
            AzureVM.token = result['access_token'];
        } else {
            throw 'Auth response does not contain access token.';
        }
    }
    catch (error) {
        data.errors.auth = error.toString();
    }

    if (!('auth' in data.errors)) {
        try {
            health = AzureVM.request('https://management.azure.com' + AzureVM.params.resource_id + '/providers/Microsoft.ResourceHealth/availabilityStatuses?api-version=2020-05-01');
            if ('value' in health && Array.isArray(health.value) && health.value.length > 0 && 'properties' in health.value[0] && typeof health.value[0].properties === 'object') {
                data.health = health.value[0].properties;
            }
        }
        catch (error) {
            data.errors.health = error.toString();
        }

        for (var i = 0; i < metrics.length; i += 20) {
            var chunk = metrics.slice(i, i + 20);

            prepared_metrics.push(
                chunk.map(function(element) {
                    return encodeURIComponent(element);
                }).join(',')
            );
        }

        start_date = new Date((new Date().getTime()) - 300000).toISOString().replace(/\.\d+/, '');
        end_date = new Date().toISOString().replace(/\.\d+/, '');
        
        for (var j in prepared_metrics) {
            try {
                metrics_data = AzureVM.request('https://management.azure.com' + AzureVM.params.resource_id + '/providers/Microsoft.Insights/metrics?metricnames=' + prepared_metrics[j] + '&timespan=' + encodeURIComponent(start_date) + '/' + encodeURIComponent(end_date) + '&api-version=2021-05-01');
                if ('value' in metrics_data && Array.isArray(metrics_data.value) && metrics_data.value.length > 0) {
                    for (k in metrics_data.value) {
                        if ('name' in metrics_data.value[k] && typeof metrics_data.value[k].name === 'object' && 'value' in metrics_data.value[k].name && typeof metrics_data.value[k].name.value === 'string' && 'timeseries' in metrics_data.value[k] && Array.isArray(metrics_data.value[k].timeseries) && metrics_data.value[k].timeseries.length > 0 && 'data' in metrics_data.value[k].timeseries[0] && Array.isArray(metrics_data.value[k].timeseries[0].data) && metrics_data.value[k].timeseries[0].data.length > 2) {
                            data.metrics[metrics_data.value[k].name.value.replace(/(\s|\/)+/g, '')] = metrics_data.value[k].timeseries[0].data[metrics_data.value[k].timeseries[0].data.length - 3];
                        }
                    }
                }
            }
            catch (error) {
                data.errors[prepared_metrics[j]] = error.toString();
            }
        } 
    }
}
catch (error) {
    data.errors.params = error.toString();
}

if (Object.keys(data.errors).length !== 0) {
    errors = 'Failed to receive data:';
    for (var error in data.errors) {
        errors += '\n' + error + ' : ' + data.errors[error];
    }
    data.errors = errors;
}
else {
    data.errors = '';
}

return JSON.stringify(data);