var Azure = {
	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 + '.';
			}
		});

		Azure.params = params;
	},

	login: function () {
		var response, login = new HttpRequest();

		if (typeof Azure.params.proxy !== 'undefined' && Azure.params.proxy !== '') {
			login.setProxy(Azure.params.proxy);
		}

		login.addHeader('Content-Type: application/x-www-form-urlencoded');
		response = login.post(
			'https://login.microsoftonline.com/' + encodeURIComponent(Azure.params.tenant_id) + '/oauth2/token',
			'grant_type=client_credentials&resource=' + encodeURIComponent('https://management.azure.com/') + '&client_id=' + encodeURIComponent(Azure.params.app_id) + '&client_secret=' + encodeURIComponent(Azure.params.password)
		);

		if (login.getStatus() !== 200) {
			throw 'Login failed with status code ' + login.getStatus() + ': ' + response;
		}

		try {
			response = JSON.parse(response);
		}
		catch (error) {
			throw 'Failed to parse login session response.';
		}

		if (!response.hasOwnProperty('access_token')) {
			throw 'Authentication response does not contain access token.';
		}

		Azure.token = response['access_token'];
	},

	request: function (url) {
		var response, request = new HttpRequest();

		if (typeof Azure.params.proxy !== 'undefined' && Azure.params.proxy !== '') {
			request.setProxy(Azure.params.proxy);
		}

		if (!Azure.token) {
			throw 'Request does not contain access token.';
		}

		request.addHeader('Content-Type: application/json');
		request.addHeader('Authorization: Bearer ' + Azure.token);
		Zabbix.log(4, '[ AzureVM ] request url: ' + url);

		response = request.get(url);

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

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

	getField: function (data, path) {
		var steps = path.split('.');

		for (var i = 0; i < steps.length; i++) {
			var step = steps[i];
			if (typeof data !== 'object' || typeof data[step] === 'undefined') {
				throw 'Required field was not found: ' + path;
			}
			data = data[step];
		}

		return data;
	},

	getMetricsData: function () {
		var data = {},
			metric_endpoints = {
				'main_and_premium_metrics': '/providers/Microsoft.Insights/metrics?metricnames=' + encodeURIComponent('Percentage CPU,CPU Credits Remaining,CPU Credits Consumed,VmAvailabilityMetric,Available Memory Bytes,Network In Total,Network Out Total,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') + '&api-version=2024-02-01&timespan=PT1M',
				'disks_metrics': '/providers/Microsoft.Insights/metrics?metricnames=' + encodeURIComponent('Disk Read Bytes,Disk Write Bytes,Disk Read Operations/Sec,Disk Write Operations/Sec,Data Disk Latency,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') + '&api-version=2024-02-01&timespan=PT1M',
				'os_disk_metrics': '/providers/Microsoft.Insights/metrics?metricnames=' + encodeURIComponent('OS Disk Latency,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,Temp Disk Latency,Temp Disk Read Bytes/sec,Temp Disk Write Bytes/sec,Temp Disk Read Operations/Sec,Temp Disk Write Operations/Sec,Temp Disk Queue Depth') + '&api-version=2024-02-01&timespan=PT1M'
			};
		data.metrics = {};

		Object.keys(metric_endpoints).forEach(function (field) {
			metrics = Azure.getField(Azure.request('https://management.azure.com' + Azure.params.resource_id + metric_endpoints[field]), 'value');
			for (k in metrics) {
				key = Azure.getField(metrics[k], 'name.value').replace(/(\s|\/)+/g, '');
				if (metrics[k].timeseries.length === 0) {
					metrics[k].timeseries.push({ 'data': ['nodata'] })
				}
				data.metrics[key] = Azure.getField(metrics[k], 'timeseries.0.data.0');
			}
		});

		data.health = Azure.getField(Azure.request('https://management.azure.com' + Azure.params.resource_id + '/providers/Microsoft.ResourceHealth/availabilityStatuses?api-version=2020-05-01'), 'value.0.properties');

		return data
	}
};

try {
	Azure.setParams(JSON.parse(value));
	Azure.login();
	return JSON.stringify(Azure.getMetricsData());
}
catch (error) {
	error += (String(error).endsWith('.')) ? '' : '.';
	Zabbix.log(3, '[ AzureVM ] ERROR: ' + error);
	return JSON.stringify({ 'error': error });
}