var base_path = 'cloudsql.googleapis.com/database/postgresql/',
	obj = {};

function checkParams(params) {
	['project_id', 'time_window', 'database_id', 'token'].forEach(function (field) {
		if (typeof params !== 'object' || typeof params[field] === 'undefined' || params[field] === '') {
			throw 'Required param is not set: ' + field + '.';
		}
	});
	if (!params.time_window.match(/^[0-9]+(m|h)$/)) {
		throw 'Incorrect update interval for parameter  time_window. Valid ranges 1m-23h.';
	}
	return params;
}

function getField(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 "' + path + '" is not present in data received.';
		}
		data = data[step];
	}
	return data;
}

function getHttpData(url, token, body) {
	var request = new HttpRequest();
	if (typeof params.proxy !== 'undefined' && params.proxy !== '') {
		request.setProxy(params.proxy);
	};
	request.addHeader('Authorization: Bearer ' + token);
	request.addHeader('Content-Type: application/json');

	var response = request.post(url, JSON.stringify(body));

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

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

	if (typeof response !== 'object' || response === null) {
		throw 'Cannot process response data: received data is not an object. Check debug log for more information.';
	}

	if (request.getStatus() !== 200) {
		if (typeof (response.error && response.error.message) !== 'undefined') {
			throw response.error.message;
		}
		else {
			throw 'Failed to receive data: invalid response status code. Check debug log for more information.';
		}
	}
	return response;
};

function singleMetrics(tsd) {
	var result = {};

	for (i in tsd) {
		result[getField(tsd[i], 'labelValues.4.stringValue')] = getField(tsd[i], 'pointData.0.values.0.int64Value');
	}
	return result;
}

var params = checkParams(JSON.parse(value)),
	filter = ' | within ' + params.time_window + " | filter database_id ='" + params.database_id + "'" + " | filter database ='" + params.database_name + "'",
	j_filter = filter + ' | join',
	url = 'https://monitoring.googleapis.com/v3/projects/' + params.project_id + '/timeSeries:query',
	common_paths = ['deadlock_count', 'tuples_returned_count', 'tuples_fetched_count'],
	common_raw = getHttpData(url, params.token, { query: '{' + common_paths.map(function (path) { return base_path + path; }).join(';') + '}' + j_filter }),
	keys = getField(common_raw, 'timeSeriesDescriptor.pointDescriptors'),
	values = getField(common_raw, 'timeSeriesData.0.pointData.0.values'),
	re = /(^t_\\d+\\.value\\.)/g;

for (i in keys) {
	var value_types = ['int64Value', 'doubleValue', 'stringValue', 'boolValue'];

	for (v in value_types) {
		if (typeof values[i][value_types[v]] !== 'undefined') {
			obj[getField(keys[i], 'key').replace(re, '')] = values[i][value_types[v]];
		}
	}
}

var single_paths = ['transaction_count', 'blocks_read_count', 'tuples_processed_count', 'tuple_size'],
	single_queries = single_paths.map(function (path) { return { query: base_path + path + filter }; });

for (q in single_queries) {
	raw = getHttpData(url, params.token, single_queries[q]);
	obj = Object.assign(obj, singleMetrics(getField(raw, 'timeSeriesData')));
}

return JSON.stringify(obj);