package eu.dnetlib.data.mapreduce.dedup;

import java.util.List;
import java.util.UUID;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import eu.dnetlib.data.mapreduce.util.OafTest;
import eu.dnetlib.data.proto.FieldTypeProtos.StructuredProperty;
import eu.dnetlib.data.proto.KindProtos.Kind;
import eu.dnetlib.data.proto.OafProtos.Oaf;
import eu.dnetlib.data.proto.OafProtos.OafEntity;
import eu.dnetlib.data.proto.OafProtos.OafEntity.Builder;
import eu.dnetlib.data.proto.ResultProtos.Result;
import eu.dnetlib.data.proto.ResultProtos.Result.Instance;
import eu.dnetlib.data.proto.TypeProtos.Type;
import eu.dnetlib.data.transform.OafEntityMerger;
import org.junit.Before;
import org.junit.Test;

public class OafMergeTest {

	private List<Oaf> oafList;

	private OafEntityMerger merger;

	@Before
	public void setUp() throws Exception {

		merger = new OafEntityMerger();
		oafList = Lists.newArrayList();
		oafList.add(getOaf("0.1").setEntity(
				getEntity("id_1", null, "pid_1").setResult(
						Result.newBuilder().setMetadata(
								Result.Metadata.newBuilder().setDateofacceptance(OafTest.sf("2012-01-01"))
										.addTitle(OafTest.getStructuredproperty("vvvv Title", "main title", "dnet:dataCite_title"))
										.setResulttype(OafTest.getQualifier("publication", "dnet:result_typologies"))))).build());
		oafList.add(getOaf("0.1").setEntity(
				getEntity("id_2", "originalId_2", "pid_2").setResult(
						Result.newBuilder().setMetadata(
								Result.Metadata.newBuilder().setDateofacceptance(OafTest.sf(""))
										.addTitle(OafTest.getStructuredproperty("aaaa Title", "main title", "dnet:dataCite_title"))
										.setResulttype(OafTest.getQualifier("publication", "dnet:result_typologies"))))).build());
		oafList.add(getOaf("0.2").setEntity(
				getEntity("id_3", "originalId_2", "pid_2").setResult(
						Result.newBuilder().setMetadata(
								Result.Metadata.newBuilder().addTitle(OafTest.getStructuredproperty("cccc Title", "sub title", "dnet:dataCite_title"))
										.setResulttype(OafTest.getQualifier("publication", "dnet:result_typologies"))))).build());

		oafList.add(getOaf("0.3").setEntity(
				getEntity("id_$", null, "pid_3").setResult(
						Result.newBuilder().setMetadata(
								Result.Metadata.newBuilder().setPublisher(OafTest.sf("AMER CHEMICAL SOCXXXXXXXXXXXXXXXXX"))
										.setResulttype(OafTest.getQualifier("publication", "dnet:result_typologies"))))).build());
		oafList.add(getOaf("0.5").setEntity(
				getEntity("id_5", null, null).setResult(
						Result.newBuilder().setMetadata(
								Result.Metadata.newBuilder().addTitle(OafTest.getStructuredproperty("hhhh title", "main title", "dnet:dataCite_title"))
										.setPublisher(OafTest.sf("AMER CHEMICAL SOC X"))
										.setResulttype(OafTest.getQualifier("publication", "dnet:result_typologies")).setStoragedate(OafTest.sf("2012-11-18"))
										.setLanguage(OafTest.getQualifier("eng", "dnet:languages")).addDescription(OafTest.sf("original description")))))
				.build());
		oafList.add(getOaf("0.6").setEntity(
				getEntity("id_6", null, "pid_6").setResult(
						Result.newBuilder().setMetadata(
								Result.Metadata.newBuilder().setResulttype(OafTest.getQualifier("publication", "dnet:result_typologies"))
										.addDescription(OafTest.sf("new description"))).addInstance(OafTest.getInstance("id", "name")))).build());
	}

	@Test
	public void test_merge() {

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

		for (final Oaf oaf : oafList) {
			builder.mergeFrom(oaf);
		}

		final Result.Metadata.Builder metadata = builder.getEntityBuilder().getResultBuilder().getMetadataBuilder();
		final Iterable<StructuredProperty> filter = Iterables.filter(metadata.getTitleList(), new Predicate<StructuredProperty>() {

			@Override
			public boolean apply(final StructuredProperty sp) {
				return (sp.getQualifier() != null) && sp.getQualifier().getClassname().equals("main title");
			}
		});

		final StructuredProperty last = Iterables.getLast(filter);

		metadata.clearTitle().addAllTitle(Lists.newArrayList(last));

		System.out.println(builder.build().toString());
	}

	@Test
	public void test_merger() {

		final Oaf merge = merger.mergeEntities(null, "id", oafList).build();

		System.out.println(merge.toString());
	}

	// @Test
	// public void test_sort() {
	// Queue<Result> q = new PriorityQueue<Result>(3, DedupReducer.cmp);
	// for (Oaf oaf : oafList) {
	// q.add(oaf.getEntity().getResult());
	// }
	//
	// while (!q.isEmpty()) {
	// Result r = q.remove();
	// List<StructuredProperty> titles = r.getMetadata().getTitleList();
	// if (!titles.isEmpty()) {
	// System.out.println(titles.get(0).getValue());
	// }
	// }
	// }

	private Oaf.Builder getOaf(final String trust) {
		return Oaf.newBuilder().setKind(Kind.entity).setDataInfo(OafTest.getDataInfo(trust)).setLastupdatetimestamp(System.currentTimeMillis());
	}

	private OafEntity.Builder getEntity(final String id, final String originalId, final String pid) {
		final Builder entity =
				OafEntity.newBuilder().setType(Type.result).setId(id).addOriginalId(originalId != null ? originalId : UUID.randomUUID().toString());

		if (pid != null) {
			entity.addPid(OafTest.getStructuredproperty(pid, "class", "scheme"));
		}

		return entity;
	}

}
