const ms365 = {
	params: {},
	token: null,

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

		ms365.params = params;
	},

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

		if (typeof ms365.params.http_proxy !== 'undefined' && ms365.params.http_proxy !== '') {
			login.setProxy(ms365.params.http_proxy);
			Zabbix.log(4, '[ Microsoft 365 ] Using HTTP proxy: ' + ms365.params.http_proxy);
		}

		login.addHeader('Content-Type: application/x-www-form-urlencoded');

		response = login.post(
			'https://login.microsoftonline.com/' + encodeURIComponent(ms365.params.tenant_id) + '/oauth2/v2.0/token',
			'grant_type=client_credentials&scope=https://graph.microsoft.com/.default&client_id=' + encodeURIComponent(ms365.params.app_id) + '&client_secret=' + encodeURIComponent(ms365.params.password)
		);

		if (login.getStatus() < 200 || login.getStatus() >= 300) {
			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.';
		}

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

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

		if (typeof ms365.params.http_proxy !== 'undefined' && ms365.params.http_proxy !== '') {
			request.setProxy(ms365.params.http_proxy);
			Zabbix.log(4, '[ Microsoft 365 ] Using HTTP proxy: ' + ms365.params.http_proxy);
		}

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

		request.addHeader('Content-Type: application/json');
		request.addHeader('Authorization: Bearer ' + ms365.token);

		Zabbix.log(4, '[ Microsoft 365 ] Request url: ' + url);

		response = request.get(url);

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

		if (request.getStatus() < 200 || request.getStatus() >= 300) {
			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) {
		const 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 ms365.nullToZero(data);
	},

	nullToZero: function (data) {
		Object.keys(data).forEach(function (key) {
			if (data[key] === null) {
				data[key] = 0;
			} else if (typeof data[key] === 'object') {
				ms365.nullToZero(data[key]);
			}
		});

		return data;
	},

	getMetricsData: function (endpoints) {
		const data = {};

		data.metrics = {};
		endpoints.forEach(function (field) {
			link = 'https://graph.microsoft.com/beta/reports/' + field + '(period=\'D7\')?$format=application/json';
			answer = ms365.getField(ms365.request(link), 'value');

			data.metrics[field] = answer;
		});

		return data;
	},

	getServiceData: function () {
		var data = {},

		link = 'https://graph.microsoft.com/beta/admin/serviceAnnouncement/healthOverviews/';
		data.services = ms365.request(link);

		return data;
	}
};


endpoints = [
	'getSharePointActivityFileCounts',
	'getSharePointActivityUserCounts',
	'getSharePointActivityPages',
	'getSharePointSiteUsageFileCounts',
	'getSharePointSiteUsageSiteCounts',
	'getSharePointSiteUsageStorage',
	'getSharePointSiteUsagePages'
];

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