var Kube = {
	params: {},

	setParams: function (params) {
		['api_url', 'api_token', 'kubelet_scheme', 'kubelet_port'].forEach(function (field) {
			if (typeof params !== 'object' || typeof params[field] === 'undefined'
				|| params[field] === '') {
				throw 'Required param is not set: "' + field + '".';
			}
		});
		['node_filter_labels', 'node_filter_annotations'].forEach(function (field) {
			if (typeof params !== 'object' || typeof params[field] === 'undefined') {
				throw 'Parameter can be empty but not removed: "' + 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;

	},

	parseFilters: function (csv) {
		if (!csv)
			return [];

		var filters = [];
		const filterCapture = /([!\w\-\.\/]+)\s*:\s*(.*)/;
		const onComma = /\s*,\s*/;

		csv.split(onComma).forEach(function (kv) {
			var match = kv.match(filterCapture);
			if (!match) {
				Zabbix.log(3, 'Cannot parse filter from: "' + kv + '"');
				return;
			}

			filters.push({ key: match[1], expression: match[2] });
		});

		return filters;
	},

	filter: function (name, data, filters) {
		if (typeof data !== 'object') {
			return true;
		}

		return filters.every(function (filter) {
			const filter_key = filter.key.startsWith('!') ? filter.key.substring(1) : filter.key;

			if (!(filter_key in data)) {
				return true;
			}

			const isExcludingFilter = filter.key.startsWith('!');
			const isMatchForFilter = new RegExp(filter.expression).test(data[filter_key]);

			if ((isExcludingFilter && isMatchForFilter) ||
				(!isExcludingFilter && !isMatchForFilter)) {
				Zabbix.log(4, '[ Kubernetes ] Discarded "' + name + '" by filter "' + filter.key + ': ' + filter.expression + '"');
				return false;
			}

			return true;
		});
	},

	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');
		if (typeof result !== 'object'
			|| typeof result.items === 'undefined') {
			throw 'Cannot get nodes from Kubernetes API. Check debug log for more information.';
		};
		var nodes = result.items,
			IPv4 = /(?:\d{1,3}\.){3}\d{1,3}/,
			kubeNodes = [],
			hostname = Kube.params.api_url.match(/https?:\/\/([\w.-]+|\[[a-f0-9:]+\]|[^a-zA-Z:]+)(?::\d+)?/),
			filterNodeLabels = Kube.parseFilters(Kube.params.node_filter_labels),
			filterNodeAnnotations = Kube.parseFilters(Kube.params.node_filter_annotations);

		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.';
		};

		kubeNodes = nodes.map(function (node) {
			if (Kube.filter(Kube.getField(node, 'metadata.name'), Kube.getField(node, 'metadata.labels'), filterNodeLabels)
				&& Kube.filter(Kube.getField(node, 'metadata.name'), Kube.getField(node, 'metadata.annotations'), filterNodeAnnotations)) {
				Zabbix.log(4, '[ Kubernetes ] Filtered node "' + node.metadata.name + '"');

				var internalIPs = Kube.getField(node, 'status.addresses').filter(function (addr) {
					return addr.type === 'InternalIP';
				});

				var internalIP = internalIPs.length && internalIPs[0].address;

				return {
					'{#NAME}': node.metadata.name,
					'{#IP}': internalIP,
					'{#KUBE.KUBELET.URL}': Kube.params.kubelet_scheme + '://' + (IPv4.test(internalIP) ? internalIP : '[' + internalIP + ']') + ':' + Kube.params.kubelet_port,
					'{#COMPONENT}': 'Kubelet',
					'{#CLUSTER_HOSTNAME}': hostname[1]
				};
			}
		});

		return JSON.stringify(kubeNodes);

	},
};

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