var Aranet = {
	params: {},
	auth_token: null,
	refresh_token: null,
	space_id: null,

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

		Aranet.params = params;
		if (typeof Aranet.params.api_endpoint === 'string') {
			if (!Aranet.params.api_endpoint.endsWith('/')) {
				Aranet.params.api_endpoint += '/';
			}
		}
	},

	request: function (method, query, data) {
		var response,
			request = new HttpRequest(),
			url = Aranet.params.api_endpoint + query;

		request.addHeader('Content-Type: application/json');

		if (Aranet.auth_token !== null) {
			request.addHeader('Authorization: Bearer ' + Aranet.auth_token);
		}

		if (typeof data !== 'undefined') {
			data = JSON.stringify(data);
		}

		switch (method) {
			case 'get':
				response = request.get(url, data);
				break;

			case 'post':
				response = request.post(url, data);
				break;

			default:
				throw 'Unsupported HTTP request method: ' + method;
		}

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

		if (request.getStatus() < 200 || request.getStatus() >= 300) {
			var message = 'Request failed with status code ' + request.getStatus();

			message += ': ' + response;
			throw message;
		}

		if (response !== null) {
			try {
				response = JSON.parse(response);
			}
			catch (error) {
				throw 'Failed to parse response received from Aranet Cloud. Check debug log for more information.';
			}
		}

		return {
			status: request.getStatus(),
			response: response
		};
	},

	login: function () {
		var result,
			data = {
				login: Aranet.params.username,
				passw: Aranet.params.password
			};

		result = Aranet.request('post', 'user/login', data);
		if (typeof result.response !== 'object'
				|| typeof result.response.auth === 'undefined'
				|| result.status != 200) {
			throw 'Cannot login to Aranet Cloud. Check debug log for more information.';
		}

		Aranet.auth_token = result.response.auth;
		Aranet.refresh_token = result.response.refresh;

		var spaces = result.response.spaces;
		for (var key in spaces) {
			if (spaces[key] == Aranet.params.space_name) {
				Aranet.space_id = key;
				break;
			}
		}

		return result.response;
	},

	logout: function () {
		var result,
			data = {
				refresh: Aranet.refresh_token
			};

		try {
			result = Aranet.request('post', 'user/logout', data);
			if (result.status != 204) {
				throw 'Cannot logout from Aranet Cloud ' + request.getStatus() + ': ' + result.response;
			}
		}
		catch (error) {
			Zabbix.log(4, '[ Aranet scraper ] ' + error)
		}
	},

	getMetrics: function () {
		var result = Aranet.request('get', 'metrics/' + Aranet.space_id);

		if (typeof result.response !== 'object'
				|| typeof result.response.data === 'undefined'
				|| result.status != 200) {
			throw 'Cannot get metrics data from Aranet Cloud. Check debug log for more information.';
		};

		return result.response;
	},

	getSensors: function () {
		var result = Aranet.request('get', 'sensors/' + Aranet.space_id + '?fields=devices,metrics,telemetry,name');

		if (typeof result.response !== 'object'
				|| typeof result.response.data === 'undefined'
				|| result.status != 200) {
			throw 'Cannot get sensors data from Aranet Cloud. Check debug log for more information.';
		};

		return result.response;
	},

	getGateways: function () {
		var result = Aranet.request('get', 'gateways/' + Aranet.space_id);

		if (typeof result.response !== 'object'
			|| typeof result.response.devices === 'undefined'
			|| result.status != 200) {
			throw 'Cannot get gateways data from Aranet Cloud. Check debug log for more information.';
		};

		return result.response;
	}
}

var processed_metrics = {},
	processed_sensors = [];

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

	Aranet.login();

	var raw_metrics = Aranet.getMetrics(),
		raw_sensors = Aranet.getSensors(),
		raw_gateways = Aranet.getGateways();

	Aranet.logout();

	var items = raw_metrics.data.items;
	for (item_idx in items) {
		var unit_name,
			units = items[item_idx].units;

		units.some(function (unit) {
			unit_name = unit.name;
			if (unit.selected) {
				return true;
			}
		});

		processed_metrics[items[item_idx].id] = {
			name: items[item_idx].name,
			unit: unit_name
		}

		delete items[item_idx];
	}

	var items = raw_sensors.data.items;
	for (item_idx in items) {
		var upd_ts = 0,
			gateway = {},
			sensor_metrics = [],
			metrics = items[item_idx].metrics,
			telemetry = items[item_idx].telemetry;

		for (m_idx in metrics) {
			var unit = processed_metrics[metrics[m_idx].id];

			if (upd_ts < metrics[m_idx].t) {
				upd_ts = metrics[m_idx].t;
			}

			sensor_metrics.push({
				name: unit.name,
				unit: unit.unit,
				value: metrics[m_idx].v
			});
		}

		for (var t_idx in telemetry) {
			var unit = processed_metrics[telemetry[t_idx].id];

			if (upd_ts < telemetry[t_idx].t) {
				upd_ts = telemetry[t_idx].t;
			}

			sensor_metrics.push({
				name: unit.name,
				unit: unit.unit,
				value: telemetry[t_idx].v
			});
		}

		raw_gateways.devices.some(function (dev) {
			if (items[item_idx].devices[0].id === dev.id) {
				gateway = {
					id: dev.id,
					name: dev.device
				}
				return true;
			}
		})

		if (upd_ts) {
			sensor_metrics.push({
				name: 'Last update',
				unit: 's',
				value: upd_ts
			});
		}

		var sensor_id = parseInt(items[item_idx].id).toString(16).slice(-5);

		processed_sensors.push({
			id: sensor_id,
			name: items[item_idx].name.trim() === '' ? sensor_id : items[item_idx].name,
			gateway: gateway,
			metrics: sensor_metrics
		});

		delete items[item_idx];
	}

	return JSON.stringify(processed_sensors);
}
catch (error) {
	Zabbix.log(3, '[ Aranet scraper ] ERROR: ' + error);
	throw 'Scraping failed: ' + error;
}