package eu.dnetlib.data.utility.featureextraction.dataprovider;

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

import java.util.Arrays;
import java.util.List;

import javax.xml.ws.wsaddressing.W3CEndpointReference;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnit44Runner;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import eu.dnetlib.common.resultset.ResultsetProperties;
import eu.dnetlib.common.ws.dataprov.DataProviderException;
import eu.dnetlib.common.ws.dataprov.IDataProviderExt;
import eu.dnetlib.common.ws.dataprov.ResultsResponse;
import eu.dnetlib.data.utility.featureextraction.Feature;
import eu.dnetlib.data.utility.featureextraction.FeatureExtractionException;
import eu.dnetlib.data.utility.featureextraction.mock.DaoMock;
import eu.dnetlib.data.utility.featureextraction.mock.IResultSetMock;
import eu.dnetlib.data.utility.featureextraction.mock.PluginMock;
import eu.dnetlib.data.utility.featureextraction.mock.ResultSetServiceMock;
import eu.dnetlib.data.utility.featureextraction.plugin.PluginFactory;
import eu.dnetlib.enabling.resultset.rmi.ResultSetException;
import eu.dnetlib.enabling.resultset.rmi.ResultSetService;
import eu.dnetlib.enabling.tools.ServiceResolver;

@RunWith(MockitoJUnit44Runner.class)
public class DataproviderTest {

	private transient FeatureExtractionDataProvider dp;
	
	@Mock
	private transient ServiceResolver resolver;
	
	private final String srcDataProviderAddress = "http://blub.blub";
	
	private transient ResultSetServiceMock srcRsService;
	
	private transient IResultSetMock sinkRsService;
	
	private transient Feature f;
	
	private transient ResultsetProperties rsProps;
	
	@Mock
	private transient PluginFactory pluginFac;
	
	private transient PluginMock plugin;
	
	private transient DaoMock dao;
	
	private transient ThreadPoolTaskExecutor taskExecutor;
	
	@Before
	public void setUp() throws ResultSetException{
		dao = new DaoMock();
		taskExecutor = new ThreadPoolTaskExecutor();
		taskExecutor.setCorePoolSize(1);
		taskExecutor.setMaxPoolSize(2);
		taskExecutor.setQueueCapacity(3);		
		taskExecutor.afterPropertiesSet();
		 
		f = new Feature();
		f.setName("someFeature");
		
		plugin = new PluginMock();
		plugin.setDao(dao);
		when(pluginFac.getPlugin(f.getName() + "_plugin")).thenReturn(plugin);
		
		rsProps = new ResultsetProperties();
		rsProps.setExpiryTime(0);
		
		sinkRsService = new IResultSetMock();
		
		srcRsService = new ResultSetServiceMock();
		String[] srcElements = {"1", "2", "3", "4", "5"};
		srcRsService.populateRS(null, Arrays.asList(srcElements));

		when(resolver.getService(eq(ResultSetService.class), argThat(new ArgumentMatcher<W3CEndpointReference>() {
			@Override
			public boolean matches(Object argument) {
				W3CEndpointReference arg = (W3CEndpointReference) argument;
				return arg.toString().contains(srcDataProviderAddress);
			}
		})) ).thenReturn(srcRsService);
		
		dp = new FeatureExtractionDataProvider();
		dp.setServiceResolver(resolver);
		dp.setResultsetProperties(rsProps);
		dp.setPluginFactory(pluginFac);
		dp.setTaskExecutor(taskExecutor);
	}
	
	@Test
	public void testCreate() throws FeatureExtractionException, DataProviderException, InterruptedException{
		System.out.println("Test:crs");
		W3CEndpointReference epr = dp.createResultSet(f, buildEpr(srcDataProviderAddress), sinkRsService);
		assertNotNull(epr);
		assertNotNull(plugin.getDao());
		assertNotNull(plugin.getProperties());
		String bdId = sinkRsService.getBdId();
		assertNotNull(bdId);
		System.out.println("Test:gbd");
		List<String> results = dp.getBulkData(bdId, 0, 10);
		assertNotNull(results);
		if (results.size() == 0)
			Thread.sleep(1000);
		System.out.println("RES SIZE:" +results.size());
		System.out.println("RES VALUE:" +results.get(0));
		ResultsResponse response = dp.getNumberOfResults(bdId);
		System.out.println("GET NUM OF RES:" +response.getTotal());

		assertNotNull(response);
		assertEquals("open", response.getStatus());
		assertEquals(1, response.getTotal());
		assertEquals("1", plugin.nextRecord()); // 1
		//System.exit(1);
		
		plugin.getDao().addResults(Arrays.asList("1"));
		//dp.updateBulkData(bdId, IDataProviderExt.STATUS_OPEN);
		
		response = dp.getNumberOfResults(bdId); 
		assertNotNull(response);
		assertEquals("open", response.getStatus());
		assertEquals(2, response.getTotal());
		results = dp.getBulkData(bdId, 0, 10);
		assertNotNull(results);
		assertEquals(2, results.size());
		
		plugin.getDao().addResults(Arrays.asList(plugin.nextRecord())); // 2
		//dp.updateBulkData(bdId, IDataProviderExt.STATUS_OPEN);
		plugin.getDao().addResults(Arrays.asList(plugin.nextRecord())); // 3
		//dp.updateBulkData(bdId, IDataProviderExt.STATUS_OPEN);
		plugin.getDao().addResults(Arrays.asList(plugin.nextRecord())); // 4
		//dp.updateBulkData(bdId, IDataProviderExt.STATUS_OPEN);
		//plugin.getDao().addResults(Arrays.asList(plugin.nextRecord())); // 5
		//dp.updateBulkData(bdId, IDataProviderExt.STATUS_OPEN);
		//assertNull(plugin.nextRecord());
		
		response = dp.getNumberOfResults(bdId); 
		assertNotNull(response);
		//assertEquals("open", response.getStatus());
		assertEquals(5, response.getTotal());
		results = dp.getBulkData(bdId, 0, 10);
		System.out.println(results.size());
		assertNotNull(results);
		assertEquals(5, results.size());
		
		//dp.updateBulkData(bdId, IDataProviderExt.STATUS_CLOSED);
		
		response = dp.getNumberOfResults(bdId); 
		assertNotNull(response);
		assertEquals("closed", response.getStatus());
	}
	
	
	private W3CEndpointReference buildEpr(String serviceAddress){
		W3CEndpointReferenceBuilder builder = new W3CEndpointReferenceBuilder();
		builder.address(serviceAddress);
		return builder.build();
	}
}
