package org.openfs.fileservice.stats;

import java.text.NumberFormat;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.apache.camel.Exchange;
import org.apache.camel.util.ObjectHelper;

public class Measurement {

	private final String name;
	private Map<String, Object> tags = new TreeMap<String, Object>();
	private Map<String, Object> fields = new LinkedHashMap<String, Object>();
	
	public Measurement(String measurement) {
		this.name = sanitize(measurement);
	}
	
	Function<Entry<String, Object>, String> formatPair = (e) -> {
		return e.getKey() + "=" + e.getValue();
	};

	public void addTag(String tagName, String tagValue) {
		if (ObjectHelper.isNotEmpty(tagValue))
			tags.put(tagName, sanitize(tagValue));
	}

	public void addField(String fieldName, String fieldValue) {
		if (ObjectHelper.isNotEmpty(fieldValue))
			fields.put(fieldName,
					"\"" + sanitize(fieldValue).replace("\"", "\\\"") + "\"");
	}

	public void addField(String fieldName, int fieldValue) {
		fields.put(fieldName, Integer.toString(fieldValue) + 'i');
	}

	public void addField(String fieldName, long fieldValue) {
		fields.put(fieldName, Long.toString(fieldValue));
	}

	public void addField(String fieldName, double fieldValue) {
		NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH);
		numberFormat.setMaximumFractionDigits(340);
		numberFormat.setGroupingUsed(false);
		numberFormat.setMinimumFractionDigits(1);
		fields.put(fieldName, numberFormat.format(fieldValue));
	}

	public  void evaluateFieldHeader(String fieldHeader, Exchange exchange) {
		if (exchange.getIn().getHeader(fieldHeader) != null) {
			Object value = exchange.getIn().getHeader(fieldHeader);
			if (value instanceof Long) {
				addField(fieldHeader, exchange.getIn().getHeader(fieldHeader, Long.class));
			} else if (value instanceof Integer) {
				addField(fieldHeader, exchange.getIn().getHeader(fieldHeader, int.class));
			} else if (value instanceof String) {
				addField(fieldHeader, exchange.getIn().getHeader(fieldHeader, String.class));
			} else if (value instanceof Double) {
				addField(fieldHeader, exchange.getIn().getHeader(fieldHeader, Double.class));
			}
		}
	}

	public  void evaluateTagHeaders(String tagHeaders, Exchange exchange) {
		String[] headers = tagHeaders.split(",");
		for (String h : headers) {
			String tagValue = MetaKeywords.replace(h, exchange);
			addTag(h.replaceFirst("%", ""), tagValue);
		}
	}

	public void export(String endpointUrl, Exchange exchange) {
		exchange.getContext().createProducerTemplate()
				.sendBodyAndHeaders(endpointUrl, this.toString(), this.tags);
	}

	public void reset() {
		if (tags != null) {
			tags.clear();
		}
		if (fields != null) {
			fields.clear();
		}
	}

	@Override
	public String toString() {

		if (tags.isEmpty()) {
			return null;
		}

		if (fields.isEmpty()) {
			return null;
		}

		// measurement,tag=val field=val ts
		StringBuilder sb = new StringBuilder(name + ",");
		// tags (tagName sorted)
		sb.append(tags.entrySet().stream().map(formatPair)
				.collect(Collectors.joining(",")));
		sb.append(" ");
		sb.append(fields.entrySet().stream().map(formatPair)
				.collect(Collectors.joining(",")));
		sb.append(" ");
		sb.append(System.currentTimeMillis()).append("000000\n");
		return sb.toString();
	}

	private String sanitize(String s) {
		return s.replace(",", "\\,").replace("=", "\\=").replace(" ", "\\ ");
	}
}
