package search.inno;

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

import java.io.File;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import bean.Content;
import bean.InnoResult;
import bean.Track;
import constants.TestConstants;

public class TestInnoSearcher {
	
	private static final Logger logger = Logger.getLogger(TestInnoSearcher.class);
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		PropertyConfigurator.configure("log4j.properties");
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void should_identify_all_if_all_is_indexed() {
	
		List<Content> contents = new ArrayList<Content>();
		for (File file : TestConstants.audioToSearch) {
			contents.add(new Content(this.getContentId(file), file));
		}
		
		InnoSearcher searcher = new InnoSearcher();
		
		searcher.indexAll(contents);
				
		int seconds = 10;
		LocalDateTime initial = LocalDateTime.now();
		
		for (Content content : contents) {
			
			List<InnoResult> result = searcher.search(new Track(1, content.getContentFile(), initial));	
			
			assertTrue(!result.isEmpty());
			
			for (InnoResult innoResult : result) {

				logger.info("should_identify_all_if_all_is_indexed: Expected ("+content+"), actual ("+innoResult+")");
				
				assertEquals(content.getContentId(), innoResult.getContentId(), 1);
			}
			
			initial = initial.plusSeconds(seconds);
		}
	}
	
	@Test
	public void should_only_identify_indexed_content() {
		
		List<Content> contents = new ArrayList<Content>();
		contents.add(new Content(this.getContentId(TestConstants.audioToSearch[0]), TestConstants.audioToSearch[0]));
		
		InnoSearcher searcher = new InnoSearcher();
		
		searcher.indexAll(contents);
		
		List<InnoResult> result = searcher.search(new Track(1, TestConstants.audioToSearch[0], LocalDateTime.now()));
		
		assertTrue(!result.isEmpty());
		
		for (InnoResult content : result) {
			
			assertEquals(contents.get(0).getContentId(), content.getContentId());
		}
		
		result = searcher.search(new Track(3, TestConstants.audioToSearch[2], LocalDateTime.now()));
		
		assertTrue(result.isEmpty());
	}
	
	@Test
	public void should_accept_on_the_fly_indexing() throws Exception {
		
		List<Content> contents = new ArrayList<Content>();
		contents.add(new Content(this.getContentId(TestConstants.audioToSearch[0]), TestConstants.audioToSearch[0]));
		
		InnoSearcher searcher = new InnoSearcher();
		
		searcher.indexAll(contents);
		
		List<InnoResult> result = searcher.search(new Track(1, TestConstants.audioToSearch[0], LocalDateTime.now()));
		
		assertTrue(!result.isEmpty());
		
		for (InnoResult content : result) {
			
			assertEquals(contents.get(0).getContentId(), content.getContentId());
		}
		
		result = searcher.search(new Track(3, TestConstants.audioToSearch[2], LocalDateTime.now()));
				
		assertTrue(result.isEmpty());
		
		contents.clear();
		
		contents.add(new Content(this.getContentId(TestConstants.audioToSearch[2]), TestConstants.audioToSearch[2]));
		
		searcher.indexAll(contents);
		
		Thread.sleep(2000);
		
		result = searcher.search(new Track(3, TestConstants.audioToSearch[2], LocalDateTime.now()));
		
		assertTrue(!result.isEmpty());
		
		for (InnoResult content : result) {
			
			assertEquals(contents.get(0).getContentId(), content.getContentId());
		}
	}
	
	@Test
	public void should_return_nothing_if_index_is_empty() {
		
		InnoSearcher searcher = new InnoSearcher();
		
		for (File file : TestConstants.audioToSearch) {
			
			List<InnoResult> result = searcher.search(new Track(1, file, LocalDateTime.now()));
			
			assertTrue(result.isEmpty());
		}		
	}
	
	@Test
	public void should_be_able_to_clean_up_index() {		
		
		List<Content> contents = new ArrayList<Content>();
		for (File file : TestConstants.audioToSearch) {
			contents.add(new Content(this.getContentId(file), file));
		}
		
		InnoSearcher searcher = new InnoSearcher();
		
		searcher.indexAll(contents);
				
		int seconds = 10;
		LocalDateTime initial = LocalDateTime.now();
		
		for (Content content : contents) {
			
			List<InnoResult> result = searcher.search(new Track(1, content.getContentFile(), initial));	
			
			assertTrue(!result.isEmpty());
			
			for (InnoResult innoResult : result) {

				logger.info("should_identify_all_if_all_is_indexed: Expected ("+content+"), actual ("+innoResult+")");
				
				assertEquals(content.getContentId(), innoResult.getContentId(), 1);
			}
			
			initial = initial.plusSeconds(seconds);
		}
		
		searcher.clear();
		
		for (Content content : contents) {
			
			List<InnoResult> result = searcher.search(new Track(1, content.getContentFile(), initial));
			
			assertTrue(result.isEmpty());
		}
	}
	
	private final int getContentId(File content) {
		
		return Integer.parseInt(content.getName().replaceAll(".mp3", ""));
	}
}
