var Kube = {
	params: {},

	setParams: function (params) {
		['api_token', 'api_url', 'api_server_scheme', 'api_server_port', 'controller_scheme', 'controller_port',
			'scheduler_scheme', 'scheduler_port', 'control_plane_taint'].forEach(function (field) {
				if (typeof params !== 'object' || typeof params[field] === 'undefined'
					|| params[field] === '') {
					throw 'Required param is not set: "' + field + '".';
				}
			});

		Kube.params = params;
		if (typeof Kube.params.api_url === 'string' && !Kube.params.api_url.endsWith('/')) {
			Kube.params.api_url += '/';
		}
	},

	apiRequest: function (query) {
		var request = new HttpRequest(),
			response,
			url = encodeURI(Kube.params.api_url + query);
		if (typeof Kube.params.http_proxy !== 'undefined' && Kube.params.http_proxy !== '') {
			request.setProxy(Kube.params.http_proxy);
		}
		request.addHeader('Content-Type: application/json');
		request.addHeader('Authorization: Bearer ' + Kube.params.api_token);

		Zabbix.log(4, '[ Kubernetes ] Sending request: ' + url);

		if (Kube.params.http_proxy) {
			Zabbix.log(4, '[ Kubernetes ] Using http proxy: ' + Kube.params.http_proxy);
		}

		response = request.get(url);

		Zabbix.log(4, '[ Kubernetes ] 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 {
			response = JSON.parse(response);
		}
		catch (error) {
			throw 'Failed to parse response received from Kubernetes API. Check debug log for more information.';
		}
		return response;
	},

	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;
	},

	getNodes: function () {
		var result = Kube.apiRequest('api/v1/nodes?labelSelector=' + Kube.params.control_plane_taint);

		if (typeof result !== 'object'
			|| typeof result.items === 'undefined') {
			throw 'Cannot get control plane nodes from Kubernetes API. Check debug log for more information.';
		};

		var nodes = result.items,
			IPv4 = /(?:\\d{1,3}\\.){3}\\d{1,3}/,
			controlPlaneNodes = [],
			hostname = Kube.params.api_url.match(/https?:\\/\\/([\\w.-]+|\\[[a-f0-9:]+\\]|[^a-zA-Z:]+)(?::\\d+)?/);

		if (typeof hostname[1] === 'undefined') {
			Zabbix.log(4, '[ Kubernetes ] Received incorrect Kubernetes API url: ' + api_url + '. Expected format: <scheme>://<host>:<port>');
			throw 'Cannot get hostname from Kubernetes API url. Check debug log for more information.';
		};

		controlPlaneNodes = nodes.map(function (node) {
			var internalIPs = Kube.getField(node, 'status.addresses').filter(function (addr) {
				return addr.type === 'InternalIP';
			});
			var internalIP = internalIPs.length && internalIPs[0].address;

			return {
				'{#NAME}': Kube.getField(node, 'metadata.name'),
				'{#IP}': internalIP,
				'{#KUBE.API.SERVER.URL}': Kube.params.api_server_scheme + '://' + (IPv4.test(internalIP) ? internalIP : '[' + internalIP + ']') + ':' + Kube.params.api_server_port + '/metrics',
				'{#KUBE.CONTROLLER.SERVER.URL}': Kube.params.controller_scheme + '://' + (IPv4.test(internalIP) ? internalIP : '[' + internalIP + ']') + ':' + Kube.params.controller_port + '/metrics',
				'{#KUBE.SCHEDULER.SERVER.URL}': Kube.params.scheduler_scheme + '://' + (IPv4.test(internalIP) ? internalIP : '[' + internalIP + ']') + ':' + Kube.params.scheduler_port + '/metrics',
				'{#COMPONENT.API}': 'API',
				'{#COMPONENT.CONTROLLER}': 'Controller manager',
				'{#COMPONENT.SCHEDULER}': 'Scheduler',
				'{#CLUSTER_HOSTNAME}': hostname[1]
			};
		});

		return JSON.stringify(controlPlaneNodes);
	}
};

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