package eu.dnetlib.dli.proto;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.google.common.collect.Maps;
import eu.dnetlib.data.graph.model.DNGFRelDecoder;
import eu.dnetlib.data.proto.DNGFProtos.DNGFEntity;
import eu.dnetlib.data.proto.DNGFProtos.DNGFRel;
import eu.dnetlib.data.proto.DatasetProtos.Dataset;
import eu.dnetlib.data.proto.DliFieldTypeProtos;
import eu.dnetlib.data.proto.DliProtos;
import eu.dnetlib.data.proto.FieldTypeProtos.KeyValue;
import eu.dnetlib.data.proto.PublicationProtos.Publication;
import eu.dnetlib.data.proto.TypeProtos.Type;
import eu.dnetlib.data.transform.Ontologies;
import org.apache.commons.lang3.StringUtils;

import static eu.dnetlib.data.proto.dli.ScholixObjectProtos.*;

/**
 * Created by sandro on 2/27/17.
 */
public class DngfToScholixConverter {

    public static Scholix.Builder withSource(final DNGFEntity input) {
        return Scholix.newBuilder().setSource(asScholixResource(input));
    }

    private static String getInverse(final DNGFRelDecoder decoder, final Ontologies ontologies) {
        final String inverse = ontologies.inverseOf(decoder.getRelDescriptor());
        if (StringUtils.isBlank(inverse)) {
            return "unknown";
        }
        return inverse;
    }

    public static Scholix.Builder withTarget(final DNGFEntity input, final DNGFRel rel, final Ontologies ontologies) {
        final Scholix.Builder scholix = Scholix.newBuilder()
                .setTarget(asScholixResource(input))
                .setRelationship(ScholixRelationship.newBuilder().setName(getInverse(DNGFRelDecoder.decode(rel), ontologies)).setSchema("datacite"))
                .addAllLinkprovider(rel.getCollectedfromList()
                        .stream()
                        .map(cf ->
                            ScholixEntityId.newBuilder()
		                            .setName(cf.getValue())
		                            .addIdentifiers(
			                            ScholixIdentifier.newBuilder()
			                                    .setSchema("dnetIdentifier")
			                                    .setIdentifier(cf.getKey()))
		                            .build())
                        .collect(Collectors.toList()));
        return scholix;
    }

    private static ScholixResource asScholixResource(DNGFEntity input) {

        final ScholixResource.Builder builder = ScholixResource.newBuilder();

        //Set Identifier
        builder.addAllIdentifier(input.getExtension(DliProtos.typedIdentifier)
                .stream()
                .map(id -> ScholixIdentifier.newBuilder()
                        .setIdentifier(id.getValue())
                        .setSchema(id.getQualifier().getClassid())
		                .build())
                .collect(Collectors.toMap(
		                i -> i.getIdentifier(),
		                i -> i,
		                (v1, v2) -> v1)).values());

        builder.setDnetIdentifier(input.getId());
	    builder.addAllCreator(DngfDliUtils.parseAuthor(input)
			    .stream()
	            .map(a -> ScholixEntityId.newBuilder().setName(a).build())
			    .collect(Collectors.toList()));


	    switch (input.getType()) {
			case publication: {
			builder.setObjectType(Type.publication.name());
		    final Publication.Metadata pm = input.getPublication().getMetadata();
		    if (pm.getTitleCount() > 0) {
		    	builder.setTitle(pm.getTitleList().stream()
					    .map(t -> t.getValue())
					    .findFirst().get());
		    }
		    builder.setPublicationDate(pm.getDateofacceptance().getValue());
				final Set<String> publishers = DngfDliUtils.parsePublishers(input);
				if (publishers != null) {
					publishers.forEach(publisher -> builder.addPublisher(ScholixEntityId.newBuilder().setName(publisher)));
				}
				break;
			}
			case dataset: {
				builder.setObjectType(Type.dataset.name());
				final Dataset.Metadata dm = input.getDataset().getMetadata();
				if (dm.getTitleCount() > 0) {
					builder.setTitle(dm.getTitleList().stream()
							.map(t -> t.getValue())
							.findFirst().get());
				}

				builder.setPublicationDate(dm.getDateofacceptance().getValue());
				final Set<String> publishers = DngfDliUtils.parsePublishers(input);
				if (publishers != null) {
					publishers.forEach(publisher -> builder.addPublisher(ScholixEntityId.newBuilder().setName(publisher)));
				}
				break;
			}
			case unknown:
		    builder.setObjectType(Type.unknown.name());
		    break;
	    case datasource:
	    case organization:
	    case person:
	    case project:
			throw new IllegalArgumentException("cannot transform type: " + input.getType());
	    }

	    final Map<String, ScholixCollectedFrom> datasources = Maps.newHashMap();
	    if (input.getCollectedfromCount() > 0) {
	    	input.getCollectedfromList().forEach(cf -> datasources.put(
	    			cf.getKey(),
				    getScholixCollectedFrom(cf, "collected", cf.getExtension(DliFieldTypeProtos.completionStatus))));
	    }
	    final List<KeyValue> resolvedFrom = input.getExtension(DliProtos.resolvedfrom);
	    if (resolvedFrom != null) {
	    	resolvedFrom.forEach(rf -> datasources.put(
				    rf.getKey(),
				    getScholixCollectedFrom(rf, "resolved", "complete")));
	    }

        builder.addAllCollectedFrom(datasources.values());
        return builder.build();
    }

	private static ScholixCollectedFrom getScholixCollectedFrom(final KeyValue rf, final String provisionMode, final String completionStatus) {
		return ScholixCollectedFrom.newBuilder()
				.setProvider(ScholixEntityId.newBuilder()
						.setName(rf.getValue())
						.addIdentifiers(ScholixIdentifier.newBuilder()
								.setIdentifier(rf.getKey())
								.setSchema("dnetIdentifier")))
				.setProvisionMode(provisionMode)
				.setCompletionStatus(completionStatus)
				.build();
	}

}
