package eu.dnetlib.data.collective.transformation.utils;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import java.util.LinkedList;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;

import eu.dnetlib.common.profile.ProfileNotFoundException;
import eu.dnetlib.data.collective.transformation.rulelanguage.RuleLanguageParser;
import eu.dnetlib.data.collective.transformation.rulelanguage.Rules;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
import eu.dnetlib.enabling.tools.ServiceLocator;

@RunWith(MockitoJUnitRunner.class)
public class TransformationRulesImportToolTest {
	// class under test
	private transient TransformationRulesImportTool importTool;
	@Mock
	private transient ISLookUpService lookupService;
	@Mock
	private transient ServiceLocator<ISLookUpService> lookupLocator;
	
	private transient RuleLanguageParser parser;
	
	@Before
	public void setUp(){
		when(lookupLocator.getService()).thenReturn(lookupService);
		importTool = new TransformationRulesImportTool();
		importTool.setLookupServiceLocator(lookupLocator);
	}
	
	@Test
	public void testGetScript() throws ISLookUpException, ProfileNotFoundException{
		List<String> queryResult = new LinkedList<String>();
		queryResult.add("script");
		when(lookupService.quickSearchProfile(anyString())).thenReturn(queryResult);
		assertEquals(1, importTool.getScript("someId").size());
	}
	
	@Test(expected = ProfileNotFoundException.class)
	public void testScriptNotFound() throws ISLookUpException, ProfileNotFoundException{
		List<String> queryResult = new LinkedList<String>();
		//queryResult.add("script");
		when(lookupService.quickSearchProfile(anyString())).thenReturn(queryResult);
		assertEquals(0, importTool.getScript("someId").size());
	}
	
	@Test(expected = IllegalStateException.class)
	public void testImportWithInvalidNumberOfSubScripts() throws ISLookUpException, ProfileNotFoundException{
		parser = new RuleLanguageParser();
		List<String> queryResult = new LinkedList<String>();
		queryResult.add(getMainScriptNoSubscripts());
		queryResult.add("importedScriptProfileId-1");
		List<String> secondQueryResult = new LinkedList<String>();
		secondQueryResult.add(getSubScript_1());
		when(lookupService.quickSearchProfile(getXQuery("MainScriptProfileId"))).thenReturn(queryResult);
		//when(lookupService.quickSearchProfile(getXQuery("importedScriptProfileId-1"))).thenReturn(secondQueryResult);
		importTool.importRules(parser, "MainScriptProfileId");
		
	}
	
	@Test
	public void testImportWithSubScripts() throws ISLookUpException, ProfileNotFoundException{
		parser = new RuleLanguageParser();
		List<String> queryResult = new LinkedList<String>();
		queryResult.add(getMainScriptWithSubscript());
		queryResult.add("importedScriptProfileId-1");
		List<String> secondQueryResult = new LinkedList<String>();
		secondQueryResult.add(getSubScript_1());
		when(lookupService.quickSearchProfile(getXQuery("MainScriptProfileId"))).thenReturn(queryResult);
		when(lookupService.quickSearchProfile(getXQuery("importedScriptProfileId-1"))).thenReturn(secondQueryResult);
		importTool.importRules(parser, "MainScriptProfileId");
		assertEquals(1, parser.getElementMappingRules().size());
		assertEquals(1, parser.getNamespaceDeclarations().size());
		assertEquals(0, parser.getFunctionCalls().size());
		assertTrue(parser.getElementMappingRules().containsKey("prefix:element"));
		Rules rule = (Rules)parser.getElementMappingRules().get("prefix:element").iterator().next(); 
		assertEquals("SomeConstantText", rule.getConstant());
	}
	
	private String getXQuery(String profileId){
		return "collection('/db/DRIVER/TransformationRuleDSResources')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value ='" +
			profileId + "']//CODE/child::node(), " +
			"for $id in (collection('/db/DRIVER/TransformationRuleDSResources')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value ='" +
			profileId + "']//IMPORTED/SCRIPT_REFERENCE/@id) return string($id)";
	}
	
	private String getMainScriptNoSubscripts(){
		StringBuilder builder = new StringBuilder();
		//builder.append("import (sub1);");
		builder.append("declare_script \"abc\";\r\n");
		builder.append("end");
		return builder.toString();
	}
	private String getMainScriptWithSubscript(){
		StringBuilder builder = new StringBuilder();
		builder.append("declare_script \"abc\";\r\n");
		builder.append("import (sub1);");
		builder.append("end");
		return builder.toString();
	}
	
	private String getSubScript_1(){
		StringBuilder builder = new StringBuilder();
		builder.append("declare_script \"sub1\";\r\n");
		builder.append("declare_ns prefix = \"someUri\";\r\n");
		builder.append("prefix:element = \"SomeConstantText\";\r\n");
		builder.append("end");
		return builder.toString();		
	}
}
