package org.col.admin.task.importer.neo;

import com.google.common.io.Files;
import org.col.admin.config.NormalizerConfig;
import org.col.admin.task.importer.neo.model.Labels;
import org.col.admin.task.importer.neo.model.NeoTaxon;
import org.col.admin.task.importer.neo.model.RelType;
import org.col.admin.task.importer.neo.model.UnescapedVerbatimRecord;
import org.col.api.RandomUtils;
import org.col.api.model.Taxon;
import org.col.api.model.TermRecord;
import org.gbif.dwc.terms.AcefTerm;
import org.gbif.dwc.terms.DcTerm;
import org.gbif.dwc.terms.DwcTerm;
import org.gbif.dwc.terms.GbifTerm;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Transaction;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Random;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

/**
 *
 */
@RunWith(Parameterized.class)
public class NeoDbTest {
  private final static Random RND = new Random();
  private final static int DATASET_KEY = 123;
  private final static NormalizerConfig cfg = new NormalizerConfig();

  @Parameterized.Parameters
  public static Collection<Object[]> data() {
    cfg.archiveDir = Files.createTempDir();
    cfg.scratchDir = Files.createTempDir();

    return Arrays.asList(new Object[][]{
        {false},
        {true}
    });
  }

  boolean persistent;
  NeoDb db;

  public NeoDbTest(boolean persistent) {
    this.persistent = persistent;
  }

  @Before
  public void init() throws IOException {
    if (persistent) {
      db = NeoDbFactory.create(DATASET_KEY, cfg);
    } else {
      db = NeoDbFactory.temporaryDb(1, 10);
    }
  }

  @After
  public void destroy() {
    if (db != null) {
      db.closeAndDelete();
    }
  }

  @Test
  public void UpdateTaxonStoreWithRelations() throws Exception {
    NeoTaxon t1;
    NeoTaxon t2;
    try (Transaction tx = db.getNeo().beginTx()) {
      t1 = db.put(taxon("12"));
      t2 = db.put(taxon("13"));

      // now relate the 2 nodes and make sure when we read the relations the instance is changed accordingly
      t1.node.createRelationshipTo(t2.node, RelType.PARENT_OF);
      t1.node.createRelationshipTo(t2.node, RelType.BASIONYM_OF);
      assertNull(t2.name.getHomotypicNameKey());

      tx.success();
    }
    db.sync();

    try (Transaction tx = db.getNeo().beginTx()) {
      NeoTaxon t1b = db.get(db.byID("12"));
      assertEquals(t1, t1b);

      NeoTaxon t2b = db.get(db.byID("13"));
      assertEquals((long) t2b.name.getHomotypicNameKey(), t1.node.getId());
    }
  }

  @Test
  public void batchProcessing() throws Exception {
    try (Transaction tx = db.getNeo().beginTx()) {
      NeoTaxon p = null;
      NeoTaxon p2 = null;
      for (int i = 1; i<100; i++) {
        NeoTaxon t = db.put(taxon("id-"+i));
        if (p == null) {
          p = t;
        } else if (p2 == null || i%10==0) {
          p2 = t;
          p.node.createRelationshipTo(p2.node, RelType.PARENT_OF);

        } else {
          p2.node.createRelationshipTo(t.node, RelType.PARENT_OF);
        }
      }
      tx.success();
    }
    db.sync();
    db.process(Labels.ALL, 5, new NeoDb.NodeBatchProcessor() {
      @Override
      public void process(Node n) {
        System.out.println("process " + n);
      }

      @Override
      public void commitBatch(int counter) {
        System.out.println("commitBatch "+counter);
      }
    });
  }

  @Test
  public void updateTaxon() throws Exception {
    try (Transaction tx = db.getNeo().beginTx()) {
      NeoTaxon t = db.put(taxon("id1"));
      tx.success();
    }
    db.sync();

    TermRecord tr = new TermRecord(123, "bla.txt", GbifTerm.VernacularName);
    tr.setType(AcefTerm.Distribution);
    tr.put(AcefTerm.DistributionElement, "Asia");

    try (Transaction tx = db.getNeo().beginTx()) {
      NeoTaxon t = db.getByID("id1");
      t.verbatim.getTerms().addExtensionRecord(AcefTerm.Distribution, tr);

      db.update(t);
    }

    try (Transaction tx = db.getNeo().beginTx()) {
      NeoTaxon t = db.getByID("id1");
      assertEquals(1, t.verbatim.getExtensionRecords(AcefTerm.Distribution).size());
      assertEquals(tr, t.verbatim.getExtensionRecords(AcefTerm.Distribution).get(0));
    }

  }

  public static NeoTaxon taxon(String id) {
    NeoTaxon t = new NeoTaxon();
    t.name = RandomUtils.randomName();
    t.taxon = new Taxon();
    t.taxon.setId(id);
    t.verbatim = UnescapedVerbatimRecord.create();
    t.verbatim.setId(id);
    t.verbatim.getTerms().put(DwcTerm.scientificName, "Abies alba");
    t.verbatim.getTerms().put(DcTerm.title, "Abies alba");
    return t;
  }
}
@@ -954,24 +954,70 @@
 sertEquals;%0A
+import static org.junit.Assert.assertNotNull;%0A
 import stati
@@ -1958,37 +1958,15 @@
 oid 
-UpdateTaxonStoreWithRelations
+neoSync
 () t
@@ -2367,24 +2367,74 @@
 ASIONYM_OF);
+%0A%0A      assertNull(t1.name.getHomotypicNameKey());
 %0A      asser
@@ -2613,38 +2613,8 @@
 ));%0A
-      assertEquals(t1, t1b);%0A%0A
     
@@ -2669,21 +2669,153 @@
 sert
-Equals((long)
+NotNull(t1b.name.getHomotypicNameKey());%0A      assertNotNull(t2b.name.getHomotypicNameKey());%0A%0A      assertEquals(t1b.name.getHomotypicNameKey(),
  t2b
@@ -2845,25 +2845,79 @@
 ey()
-,
+);%0A     
  t1
+b
 .n
-ode.getId()
+ame.setHomotypicNameKey(null);%0A      assertEquals(t1, t1b
 );%0A 

Fix NeoDbTest expectations