package eu.eudat.logic.mapper.elastic;

import eu.eudat.data.dao.criteria.DataManagementPlanCriteria;
import eu.eudat.data.entities.DMP;
import eu.eudat.elastic.criteria.DatasetCriteria;
import eu.eudat.elastic.entities.Dataset;
import eu.eudat.elastic.entities.Tag;
import eu.eudat.logic.managers.DatasetManager;
import eu.eudat.logic.services.ApiContext;
import eu.eudat.logic.utilities.helpers.StreamDistinctBy;

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

public class DatasetMapper {

	private final ApiContext apiContext;
	private final DatasetManager datasetManager;

	public DatasetMapper(ApiContext apiContext, DatasetManager datasetManager) {
		this.apiContext = apiContext;
		this.datasetManager = datasetManager;
	}

	public Dataset toElastic(eu.eudat.data.entities.Dataset dataset, List<Tag> tags) throws Exception {
		if (dataset.getProfile() == null) {
			return null;
		}
		Dataset elastic = new Dataset();
		elastic.setId(dataset.getId().toString());
		if (tags != null && !tags.isEmpty()) {
			DatasetCriteria criteria = new DatasetCriteria();
			criteria.setTags(tags);
			criteria.setHasTags(true);
			List<Tag> tags1 = apiContext.getOperationsContext().getElasticRepository().getDatasetRepository().query(criteria).stream().map(eu.eudat.elastic.entities.Dataset::getTags).flatMap(Collection::stream)
									   .filter(StreamDistinctBy.distinctByKey(Tag::getId)).filter(tag -> tags.stream().anyMatch(tag1 -> tag1.getName().equals(tag.getName()))).collect(Collectors.toList());
			if (tags1.isEmpty()) {
				tags.forEach(tag -> tag.setId(UUID.randomUUID().toString()));
				elastic.setTags(tags);
			} else {
				if (tags1.size() < tags.size()) {
					tags.stream().filter(tag -> tag.getId() == null || tag.getId().equals("")).forEach(tag -> tags1.add(new Tag(UUID.randomUUID().toString(), tag.getName())));
				}
				elastic.setTags(tags1);
			}
		}
		elastic.setLabel(dataset.getLabel());
		elastic.setDescription(dataset.getDescription());
		elastic.setTemplate(dataset.getProfile().getId());
		elastic.setStatus(dataset.getStatus());
		elastic.setDmp(dataset.getDmp().getId());
		elastic.setGroup(dataset.getDmp().getGroupId());
		elastic.setGrant(dataset.getDmp().getGrant().getId());
		elastic.setCreated(dataset.getCreated());
		elastic.setModified(dataset.getModified());
		elastic.setFinalizedAt(dataset.getFinalizedAt());
		if (dataset.getDmp().getUsers() != null) {
			elastic.setCollaborators(dataset.getDmp().getUsers().stream().map(user -> CollaboratorMapper.toElastic(user.getUser(), user.getRole())).collect(Collectors.toList()));
		}
		DataManagementPlanCriteria dmpCriteria = new DataManagementPlanCriteria();
		dmpCriteria.setAllVersions(true);
		dmpCriteria.setGroupIds(Collections.singletonList(dataset.getDmp().getGroupId()));
		apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().getWithCriteria(dmpCriteria).toList().stream()
				  .max(Comparator.comparing(DMP::getVersion)).ifPresent(dmp -> elastic.setLastVersion(dmp.getId().equals(dataset.getDmp().getId())));
		apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().getWithCriteria(dmpCriteria).toList().stream().filter(DMP::isPublic)
				  .max(Comparator.comparing(DMP::getVersion)).ifPresent(dmp -> elastic.setLastPublicVersion(dmp.getId().equals(dataset.getDmp().getId())));
		if (elastic.getLastVersion() == null) {
			elastic.setLastVersion(true);
		}
		if (elastic.getLastPublicVersion() == null) {
			elastic.setLastPublicVersion(false);
		}
		if (dataset.getDmp().getOrganisations() != null) {
			elastic.setOrganizations(dataset.getDmp().getOrganisations().stream().map(OrganizationMapper::toElastic).collect(Collectors.toList()));
		}
		elastic.setPublic(dataset.getDmp().isPublic());
		elastic.setGrantStatus(dataset.getDmp().getGrant().getStatus());
		elastic.setFormData(datasetManager.getWordDocumentText(dataset));

		return elastic;
	}
}
