package org.iri_research.renkan.test.repositories;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.iri_research.renkan.models.Space;
import org.iri_research.renkan.repositories.SpacesRepository;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.mongodb.DBCollection;
import com.mongodb.DBObject;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("repositories-context.xml")
public class SpacesRepositoryTest {
	
	private final static int SPACE_NB = 3;
	
	private Logger logger = LoggerFactory.getLogger(SpacesRepositoryTest.class);
	
	@Autowired
	private SpacesRepository spacesRepository;

	@Autowired
	private MongoTemplate mongoTemplate;
	
	private Map<String, Space> spacesList = new HashMap<String, Space>(SPACE_NB);
	private List<String> spacesUuids = new ArrayList<>(SPACE_NB);	
	
	@Before
	public void setup() {
		
		logger.debug("Setup");
		spacesRepository.deleteAll();
		for(int i=0;i<SPACE_NB;i++) {
			Date creationDate = new Date();
			String uuid = UUID.randomUUID().toString();
			spacesUuids.add(uuid);
			Space testSpace = new Space(uuid, "test " + i, "Test space " + 1, "{}", "http://ldt.iri.centrepompidou.fr", "#ababab", "test_user", "http://ldt.iri.centrepompidou.fr", creationDate);
			testSpace = spacesRepository.save(testSpace);
			this.spacesList.put(uuid, testSpace);
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	@Test
	public void testFieldMapping() {
		// query json directly with mongodb driver
		// check field values
		DBCollection coll = mongoTemplate.getCollection(mongoTemplate.getCollectionName(Space.class));
		
		for(DBObject obj: coll.find()) {
			Assert.assertTrue("mongo object must have _id field", obj.containsField("_id"));

			String id = obj.get("_id").toString();
			
			Space sp = this.spacesList.get(id);
			
			Assert.assertTrue("mongo object must have title field", obj.containsField("title"));
			Assert.assertEquals("Titles must be the same", obj.get("title"), sp.getTitle());

			Assert.assertTrue("mongo object must have description field", obj.containsField("description"));
			Assert.assertEquals("description must be the same", obj.get("description"), sp.getDescription());

			Assert.assertTrue("mongo object must have color field", obj.containsField("color"));
			Assert.assertEquals("Color must be the same", obj.get("color"), sp.getColor());

			Assert.assertTrue("mongo object must have uri field", obj.containsField("uri"));
			Assert.assertEquals("Uri must be the same", obj.get("uri"), sp.getUri());

			Assert.assertTrue("mongo object must have image field", obj.containsField("image"));
			Assert.assertEquals("Image must be the same", obj.get("image"), sp.getImage());
			
			Assert.assertTrue("mongo object must have created field", obj.containsField("created"));
			Assert.assertEquals("Created must be the same", obj.get("created"), sp.getCreated());

			Assert.assertTrue("mongo object must have bin_config field", obj.containsField("bin_config"));
			Assert.assertEquals("Uri must be the same", obj.get("bin_config"), sp.getBinConfig());

			Assert.assertTrue("mongo object must have created_by field", obj.containsField("created_by"));
			Assert.assertEquals("created by must be the same", obj.get("created_by"), sp.getCreatedBy());			
			
		}		
	}
	
	@Test
	public void testPagination() {
		
		Sort s = new Sort(Direction.DESC, "created");
		Pageable p = new PageRequest(0, 2, s);
		
		Page<Space> page = this.spacesRepository.findAll(p);
		
		Assert.assertEquals("page content length must be two", 2, page.getNumberOfElements());
		Assert.assertEquals("id must be id of last created space", this.spacesUuids.get(SPACE_NB-1), page.getContent().get(0).getId());
		Assert.assertEquals("id must be id of last created space", this.spacesUuids.get(SPACE_NB-2), page.getContent().get(1).getId());
		
		p = new PageRequest(1, 2, s);
		page = this.spacesRepository.findAll(p);
		Assert.assertEquals("page content length must be one", 1, page.getNumberOfElements());
		Assert.assertEquals("id must be id of first created space", this.spacesUuids.get(0), page.getContent().get(0).getId());
		
	}
	
	@After
	public void teardown() {
		spacesRepository.deleteAll();
	}

	
}
