package eu.eudat.models.rda.mapper;

import com.fasterxml.jackson.databind.JsonNode;
import eu.eudat.logic.utilities.helpers.MyStringUtils;
import eu.eudat.models.rda.SecurityAndPrivacy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.stream.Collectors;

public class SecurityAndPrivacyRDAMapper {
	private static final Logger logger = LoggerFactory.getLogger(SecurityAndPrivacyRDAMapper.class);

	public static List<SecurityAndPrivacy> toRDAList(List<JsonNode> nodes) {
		Map<String, SecurityAndPrivacy> rdaMap = new HashMap<>();

		for (JsonNode node: nodes) {
			String rdaProperty = node.get("rdaProperty").asText();
			String rdaValue = node.get("value").asText();
			if(rdaValue == null || rdaValue.isEmpty()){
				continue;
			}
			SecurityAndPrivacy rda = getRelative(rdaMap, node.get("numbering").asText());
			if (!rdaMap.containsValue(rda)) {
				rdaMap.put(node.get("numbering").asText(), rda);
			}
			for (ExportPropertyName exportPropertyName : ExportPropertyName.values()) {
				if (rdaProperty.contains(exportPropertyName.getName())) {
					switch (exportPropertyName) {
						case TITLE:
							rda.setTitle(rdaValue);
							rda.getAdditionalProperties().put(ImportPropertyName.TITLE.getName(), node.get("id").asText());
							break;
						case DESCRIPTION:
							rda.setDescription(rdaValue);
							rda.getAdditionalProperties().put(ImportPropertyName.DESCRIPTION.getName(), node.get("id").asText());
							break;
					}
				}
			}
		}

		return rdaMap.values().stream()
				.filter(sap -> sap.getTitle() != null)
				.collect(Collectors.toList());
	}

	public static Map<String, String> toProperties(List<SecurityAndPrivacy> rdas) {
		Map<String, String> properties = new HashMap<>();
		rdas.forEach(rda -> rda.getAdditionalProperties().entrySet().forEach(entry -> {
			try {
				ImportPropertyName importPropertyName = ImportPropertyName.fromString(entry.getKey());
				switch(importPropertyName) {
					case TITLE:
						properties.put(entry.getValue().toString(), rda.getTitle());
						break;
					case DESCRIPTION:
						properties.put(entry.getValue().toString(), rda.getDescription());
						break;
				}
			} catch (Exception e) {
				logger.error(e.getMessage(), e);
			}
		}));

		return properties;
	}

	public static SecurityAndPrivacy toRDA(JsonNode node) {
		SecurityAndPrivacy rda = new SecurityAndPrivacy();
		String rdaProperty = node.get("rdaProperty").asText();
		String value =node.get("value").asText();

		if (rdaProperty.contains("description")) {
			rda.setDescription(value);
		} 
		if (rdaProperty.contains("title")) {
			rda.setTitle(value);
		}
		
		if (rda.getTitle() == null) {
			throw new IllegalArgumentException("Security And Privacy Title is missing");
		}

		return rda;
	}

	private static SecurityAndPrivacy getRelative(Map<String, SecurityAndPrivacy> rdaMap, String numbering) {
		return rdaMap.entrySet().stream().filter(entry -> MyStringUtils.getFirstDifference(entry.getKey(), numbering) > 0)
					 .max(Comparator.comparingInt(entry -> MyStringUtils.getFirstDifference(entry.getKey(), numbering))).map(Map.Entry::getValue).orElse(new SecurityAndPrivacy());
	}

	private enum ExportPropertyName {
		TITLE("title"),
		DESCRIPTION("description");

		private String name;

		ExportPropertyName(String name) {
			this.name = name;
		}

		public String getName() {
			return name;
		}
	}

	private enum ImportPropertyName {
		TITLE("titleId"),
		DESCRIPTION("descriptionId");

		private String name;

		ImportPropertyName(String name) {
			this.name = name;
		}

		public String getName() {
			return name;
		}

		public static ImportPropertyName fromString(String name) throws Exception {
			for (ImportPropertyName importPropertyName: ImportPropertyName.values()) {
				if (importPropertyName.getName().equals(name)) {
					return importPropertyName;
				}
			}
			throw new Exception("Property not available");
		}
	}
}
