package eu.eudat.logic.mapper.elastic;

import eu.eudat.data.dao.criteria.DataManagementPlanCriteria;
import eu.eudat.data.entities.DMP;
import eu.eudat.elastic.entities.Dataset;
import eu.eudat.elastic.entities.Dmp;
import eu.eudat.elastic.entities.Tag;
import eu.eudat.logic.managers.DatasetManager;
import eu.eudat.logic.services.ApiContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

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

	private final ApiContext apiContext;
	private final DatasetManager datasetManager;
	private final DatasetMapper datasetMapper;

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

	public Dmp toElastic(DMP dmp) {
		Dmp elastic = new Dmp();
		elastic.setId(dmp.getId());
		elastic.setGroupId(dmp.getGroupId());
		if (dmp.getUsers() != null) {
			elastic.setCollaborators(dmp.getUsers().stream().map(user -> CollaboratorMapper.toElastic(user.getUser(), user.getRole())).collect(Collectors.toList()));
		}
		elastic.setDescription(dmp.getDescription());
		elastic.setGrant(dmp.getGrant().getId());
		elastic.setLabel(dmp.getLabel());
		elastic.setPublic(dmp.isPublic());
		elastic.setStatus(dmp.getStatus());
		elastic.setCreated(dmp.getCreated());
		elastic.setModified(dmp.getModified());
		elastic.setFinalizedAt(dmp.getFinalizedAt());
		elastic.setPublishedAt(dmp.getPublishedAt());
		DataManagementPlanCriteria dmpCriteria = new DataManagementPlanCriteria();
		dmpCriteria.setAllVersions(true);
		dmpCriteria.setGroupIds(Collections.singletonList(dmp.getGroupId()));
		apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().getWithCriteria(dmpCriteria).toList().stream()
				  .max(Comparator.comparing(DMP::getVersion)).ifPresent(dmp1 -> elastic.setLastVersion(dmp1.getId().equals(dmp.getId())));
		apiContext.getOperationsContext().getDatabaseRepository().getDmpDao().getWithCriteria(dmpCriteria).toList().stream().filter(DMP::isPublic)
				  .max(Comparator.comparing(DMP::getVersion)).ifPresent(dmp1 -> elastic.setLastPublicVersion(dmp1.getId().equals(dmp.getId())));
		if (elastic.getLastVersion() == null) {
			elastic.setLastVersion(false);
		}
		if (elastic.getLastPublicVersion() == null) {
			elastic.setLastPublicVersion(false);
		}
		if (dmp.getDataset() != null) {

			elastic.setDatasets(dmp.getDataset().stream().filter(dataset -> dataset.getId() != null).map(dataset -> {
				List<Tag> tags = null;
				try {
					Dataset dataset1 = apiContext.getOperationsContext().getElasticRepository().getDatasetRepository().findDocument(dataset.getId().toString());
					if (dataset1 != null) {
						tags = dataset1.getTags();
					}
					dataset.setDmp(dmp);
					return datasetMapper.toElastic(dataset, tags);
				} catch (Exception e) {
					logger.error(e.getMessage(), e);
				}
				return null;
			}).filter(Objects::nonNull).collect(Collectors.toList()));
		}
		if (dmp.getAssociatedDmps() != null) {
			elastic.setTemplates(dmp.getAssociatedDmps().stream().map(DatasetTemplateMapper::toElastic).collect(Collectors.toList()));
		}
		if (dmp.getOrganisations() != null) {
			elastic.setOrganizations(dmp.getOrganisations().stream().map(OrganizationMapper::toElastic).collect(Collectors.toList()));
		}
		if (dmp.getGrant() != null) {
			elastic.setGrantStatus(dmp.getGrant().getStatus());
		}
		return elastic;
	}
}
