package io.artur.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.sql.DataSource;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.drools.core.base.MapGlobalResolver;
import org.junit.Assert;
import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.Results;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.pandaa.test.ExpiryFact;
import org.pandaa.test.MyModel;
import org.slf4j.LoggerFactory;

import com.codahale.metrics.MetricRegistry;

import bitronix.tm.BitronixTransactionManager;
import bitronix.tm.TransactionManagerServices;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.util.Duration;

public class ExceptionTest {

	static {
		Logger rootLogger = Logger.getRootLogger();
		rootLogger.setLevel(Level.OFF);
		
		ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME);
		root.setLevel(ch.qos.logback.classic.Level.INFO);
	}
	
	ExceptionDataSource ds;
	
	@Test
	public void testExcept() {
		KieSession persistedSession = persistedSession("base");
		long id = persistedSession.getIdentifier();
		
		
		get().forEach(p -> persistedSession.insert(p));
		Assert.assertEquals(1000, persistedSession.getFactCount());
		
		try {
			persistedSession.insert(new ExpiryFact());
			persistedSession.fireAllRules();
		} catch (Exception e) {
		}
		
		ds.exceptionNext();
		
		try {
			persistedSession.insert(new ExpiryFact());
			persistedSession.fireAllRules();
		} catch (Exception e) {
		}
		
		try {
			persistedSession.insert(new ExpiryFact());
			persistedSession.fireAllRules();
		} catch (Exception e) {
		}
		
		ds.exceptionNext();
		
		try {
			persistedSession.insert(new ExpiryFact());
			persistedSession.fireAllRules();
		} catch (Exception e) {
		}
		
		
		boolean npe = false;
		
		try {
			persistedSession.insert(new ExpiryFact());
			persistedSession.fireAllRules();
		} catch (Exception e) {
			Throwable cause = e.getCause();
			while(cause != null) {
				if(cause instanceof NullPointerException) {
					npe = true;
				}
				cause = cause.getCause();
			}
		}
		
		Assert.assertTrue(npe);
	}
	
	public static List<MyModel> get() {
		List<MyModel> res = new ArrayList<>();
		for(int i=0; i< 1000; i++) {
			MyModel m = new MyModel();
			m.asked = i % 10 + 1;
			String string = UUID.randomUUID().toString();
			m.setName(string);
			res.add(m);
		}
		return res;
	}
	
	public KieSession persistedSession(String baseId) {
		BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager();
		Map<Object, Object> properties = new HashMap<>();
		properties.put(org.hibernate.cfg.Environment.DATASOURCE, ds());
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa", properties);
			
		KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
		Results verify = kContainer.verify();
		if(verify.hasMessages(org.kie.api.builder.Message.Level.ERROR)) {
			throw new IllegalStateException("Could not build KIEBase:" + verify.toString());
		}
		
		Environment env = ks.newEnvironment();
		env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
		env.set(EnvironmentName.TRANSACTION_MANAGER, tm);
		env.set(EnvironmentName.GLOBALS, new MapGlobalResolver(globals()));
		
		KieSessionConfiguration newKieSessionConfiguration = ks.newKieSessionConfiguration();
		KieBase kieBase = kContainer.getKieBase(baseId);
	
		return ks.getStoreServices().newKieSession(kieBase, newKieSessionConfiguration, env);
	}
	
	public KieSession loadSession(final long id, final String baseId) {
		BitronixTransactionManager tm = TransactionManagerServices.getTransactionManager();
		Map<Object, Object> properties = new HashMap<>();
		properties.put(org.hibernate.cfg.Environment.DATASOURCE, ds());
		EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa", properties);
			
		KieServices ks = KieServices.Factory.get();
        KieContainer kContainer = ks.getKieClasspathContainer();
		Results verify = kContainer.verify();
		if(verify.hasMessages(org.kie.api.builder.Message.Level.ERROR)) {
			throw new IllegalStateException("Could not build KIEBase:" + verify.toString());
		}
		
		Environment env = ks.newEnvironment();
		env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
		env.set(EnvironmentName.TRANSACTION_MANAGER, tm);
		env.set(EnvironmentName.GLOBALS, new MapGlobalResolver(globals()));
		
		KieSessionConfiguration newKieSessionConfiguration = ks.newKieSessionConfiguration();
		KieBase kieBase = kContainer.getKieBase(baseId);
		return ks.getStoreServices().loadKieSession(id, kieBase, newKieSessionConfiguration, env);
	}
	
	public Map<String, Object> globals() {
		return Collections.emptyMap();
	}
	
	public DataSource ds() {
		if(ds == null) {
			DataSourceFactory factory = new DataSourceFactory();
			factory.setUrl(getUrl());
			factory.setUser(getUser());
			factory.setPassword(getPassword());
			factory.setValidationQuery("SELECT 1");
			factory.setMinSize(8);
			factory.setMaxSize(32);
			factory.setCheckConnectionWhileIdle(true);
			factory.setEvictionInterval(Duration.seconds(10));
			factory.setMinIdleTime(Duration.minutes(1));
			factory.setDriverClass(getDriver());
			ds = new ExceptionDataSource(factory.build(new MetricRegistry(), "test"));
		}
		return ds;
	}

	private String getDriver() {
		return "com.mysql.jdbc.Driver";
	}



	private String getPassword() {
		return "";
	}



	private String getUser() {
		return "root";
	}



	private String getUrl() {
		return "jdbc:mysql://localhost:3306/drools_test";
	}
	
}
