package com.microstar.tap3.api;

import javax.persistence.EntityManager;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.HEAD;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.slf4j.Logger;

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.sns.AmazonSNS;
import com.amazonaws.services.sns.AmazonSNSClientBuilder;
import com.amazonaws.services.sns.model.PublishRequest;
import com.amazonaws.services.sns.model.PublishResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.fluent.hibernate.cfg.scanner.EntityScanner;
import com.microstar.tap3.exceptions.InitializationException;
import com.microstar.tap3.util.ConfigSingleton;
import com.microstar.tap3.util.RestUtil;

public abstract class BaseResourceImpl
{
	public static final String 				version = "v3";
	protected static	AmazonDynamoDB 		client = null;//AmazonDynamoDBClientBuilder.defaultClient();
	protected static 	DynamoDB 			dynamo = null;
	protected static 	boolean 			SQLinitialized = false;
	protected static 	boolean 			noSQLinitialized = false;
	protected static 	Logger 				LOG = null;
	protected static 	SessionFactory		sessionFactory;
	protected static 	ServiceRegistry		serviceRegistry;
	protected static 	Session				session;
	protected static 	EntityManager		em;
	protected static 	AmazonSNS 			snsClient = null;
	protected static 	ObjectMapper 		mapper = new ObjectMapper();
	
	public BaseResourceImpl()
	{
		// TODO Auto-generated constructor stub
	}

	// Ensure that all implementors have an init method. 
	public abstract void initSQLLocal() throws InitializationException;
	
	protected void initSQL() throws InitializationException
	{
		LOG.info("BaseResource::Starting SQL initializer...");
		
		if ( SQLinitialized )
		{
			cleanup();
			return;
		}
		
		try
		{
		}
		catch ( Exception ex )
		{
			LOG.error("BaseResource::initSQL:Caught exception: " + ex.getMessage(), ex);
			throw new InitializationException(ex);
		}
		LOG.info("BaseResource::Exiting SQL initializer...");

	}

	public abstract void initDynamoLocal() throws InitializationException;
	protected void initDynamo() throws InitializationException
	{
	try {
		}
		catch ( Exception ex )
		{
			LOG.error("dynamoinit::exception: "+ ex.getMessage(), ex);
			ex.printStackTrace();
			throw new InitializationException(ex);
		}
	}
	
	@HEAD
	@Path("/ping")
	public Response ping(@QueryParam("additionalDelay") @DefaultValue("0") int additionalDelay)
	{
		LOG.info("Entering ping::" + additionalDelay);
		if ( additionalDelay < 0 )
		{
			LOG.debug("Re-initializing SQL");
			SQLinitialized = false;
			additionalDelay = 0;
			if ( session != null )
				session.close();
		}
		
		if ( !SQLinitialized )
		{
			try {
				initSQL();
			} catch (InitializationException e) {
				return RestUtil.response(Status.INTERNAL_SERVER_ERROR, RestUtil.errorMsg("::init:Caught exception:" , e.getMessage()));
			}
		}
		else
			RestUtil.sleep(additionalDelay);
		LOG.info("Exiting ping::");
		return Response
				.ok()
				.build();

	}

	public void cleanup()
	{
		if ( session.isJoinedToTransaction() )
		{
			LOG.warn("BaseResourceImpl::rolling back existing transaction");
			session.getTransaction().rollback();
		}
	}
	
	public Response options()
	{
		return Response
				.ok()
				.header("Access-Control-Allow-Headers", "Content-Type,Accept,Authentication")
				.header("Access-Control-Allow-Origin", "*")
				.build();
	}
	
	public String getUserPermissions(String userSub)
	{
		String permString = "";
		
		
		
		return permString;
	}
	
//	protected String getJWTIdentity ()
//	{
//		String ret = null;
//		
//		JWTPayload jwt = (JWTPayload) ConfigSingleton.getInstance().getProperty("jwt");
//		if ( jwt == null )
//		{
//			System.out.println("WARNING:  jwt is null in getJWTIdentity!");
//		}
//		else
//		{
//			ret = jwt.getSub();
//		}
//		
//		return ret;
//		
//	}
//	
	
	protected Session getSession() throws InitializationException
	{
		if ( session == null || !session.isOpen() || !session.isConnected() )
		{
			SQLinitialized = false;
			initSQL();
		}
		
		return session;
	}
	
	protected void beginTransaction()
	{
		if ( session != null && session.isJoinedToTransaction() )
		{
			LOG.warn("beginTransaction::Already joined to transaction, aborting!");
			session.getTransaction().commit();
		}
		
		session.beginTransaction();
	}
	
	protected void commitTransaction()
	{
		if ( session != null && ! session.isJoinedToTransaction() )
		{
			LOG.warn("commitTransaction::NOT joined to transaction!");
			return;
		}
		
		session.getTransaction().commit();
	}

	protected void abortTransaction()
	{
		if ( session != null && session.isJoinedToTransaction() )
			session.getTransaction().rollback();
	}
	
	protected void publishNotification(String customerId, String topicArnPropertyName)
	{
		if ( ConfigSingleton.getInstance().getProperty(topicArnPropertyName) == null )
		{
			LOG.warn("publishNotification::Stage Variable " + topicArnPropertyName + " is NOT set!");
			return;
		}

		PublishRequest pr = new PublishRequest();
		pr.setSubject(customerId);
		try
		{
			pr.setMessage(mapper.writeValueAsString(ConfigSingleton.getInstance()));
		} catch (JsonProcessingException e)
		{
			LOG.error("",e);
		}
		pr.setTopicArn(ConfigSingleton.getInstance().getProperty(topicArnPropertyName));
		PublishResult pResp = snsClient.publish(pr);
		LOG.debug("Published message to " + topicArnPropertyName + ": " + pResp.getMessageId());
	}
	

}
