package com.eactive.eai.adapter.http.dynamic;

import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONObject;

import com.eactive.eai.adapter.AdapterGroupVO;
import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.RequestDispatcher;
import com.eactive.eai.adapter.http.HttpStatusException;
import com.eactive.eai.adapter.http.client.HttpClientAdapterServiceKey;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilter;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterFactory;
import com.eactive.eai.adapter.http.dynamic.filter.HttpAdapterFilterType;
import com.eactive.eai.adapter.http.dynamic.filter.JwtAuthException;
import com.eactive.eai.common.TransactionContextKeys;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.TxSiftContext;
import com.eactive.eai.common.util.UUIDGenerator;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public abstract class HttpAdapterServiceSupport implements HttpAdapterService, HttpAdapterServiceKey {
	private static final String LOG_PREFIX = "HttpAdapterServiceSupport] ";
	protected long slowTranTime = 2000L;
	public static final String HEADER_NAME_CLIENT_ID = "x-elink-client-id";
	public static final String PROPERTIES_NAME_CLIENT_ID = "clientId";
	static Logger logger = Logger.getLogger(Logger.LOGGER_ADAPTER);
	private ObjectMapper mapper = new ObjectMapper();
	
	public Object service(String adptGrpName, String adptName, Object message, Properties prop,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		String uuid = prop.getProperty(TransactionContextKeys.TRANSACTION_UUID);
		boolean bMDCput = false;
		if(uuid == null) {
			uuid = UUIDGenerator.getUUID().toString().replaceAll("-", "");
			prop.setProperty(TransactionContextKeys.TRANSACTION_UUID, uuid);
		}
		
		bMDCput = TxSiftContext.begin(uuid);
		
		try {
			String transactionId = request.getHeader(HttpClientAdapterServiceKey.TRANSACTION_ID);
			if (StringUtils.isNotBlank(transactionId)) {
				prop.put(HttpClientAdapterServiceKey.TRANSACTION_ID, transactionId);
			}
			
			try {
				String clientId = request.getHeader(HEADER_NAME_CLIENT_ID);
				if (StringUtils.isNotBlank(clientId)) {
					prop.put(PROPERTIES_NAME_CLIENT_ID, clientId);
				}
				
				String instanceId = request.getHeader(HttpClientAdapterServiceKey.INSTANCE_ID);
				if (StringUtils.isNotBlank(instanceId)) {
					prop.put(HttpClientAdapterServiceKey.INSTANCE_ID, instanceId);
				}
			} catch (Exception e) {
				 logger.warn(LOG_PREFIX + "Failed to read request headers: " + e.getMessage());
			}
	
			Object obj = null;
			try {
				message = doPreFilters(adptGrpName, adptName, message, prop, request, response);
				
				if (message instanceof JSONObject) {
					message = ((JSONObject) message).toJSONString();
				} else if (message instanceof JsonNode) {
					message = mapper.writeValueAsString((JsonNode) message);
				}
				
				obj = RequestDispatcher.getRequestDispatcher(adptGrpName).handle(adptName, message, prop);
				obj = doPostFilters(adptGrpName, adptName, obj, prop, request, response);
			} catch (HttpStatusException e) { // inbound error
				logger.warn(LOG_PREFIX + transactionId + "-" + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
				throw e;
			} catch (JwtAuthException e) { // filter error
				logger.error(LOG_PREFIX + transactionId + "-" + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
//				UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, message, prop, request, response,
//						"RECEAIIRP202", e);
				throw e;
			} catch (Exception e) { // filter error
				logger.error(LOG_PREFIX + transactionId + "-" + adptGrpName + "-" + adptName + ">>" + e.getMessage(), e);
//				UnkownMessageLogUtils.logUnkownMessage(adptGrpName, adptName, message, prop, request, response,
//						"RECEAIIRP201", e);
				throw e;
			}
			
			if (obj == null) {
				return null;
			} else if (obj instanceof byte[]) {
				return (byte[]) obj;
			} else if (obj instanceof String) {
				return (String) obj;
			} else if (obj instanceof JSONObject) {
				return ((JSONObject) obj).toJSONString();
			} else if (obj instanceof JsonNode) {
				return (JsonNode) obj;
			} else {
				throw new Exception("RECEAIAHA001");
			}
		} finally {
			if(bMDCput)
				TxSiftContext.end();
		}
	}

	private Object doPreFilters(String adptGrpName, String adptName, Object message, Properties prop,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		AdapterManager manager = AdapterManager.getInstance();
		AdapterGroupVO group =  manager.getAdapterGroup(adptGrpName);
		
		if (!"HTC".equals(group.getType())) {
			String allowIp = prop.getProperty(ALLOW_IP,"");
			if (StringUtils.isNotBlank(allowIp)) {
				HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(HttpAdapterFilterType.ADAPTERALLOWIPLISTFILTER.toString());
				if (adapterFilter != null) {
					message = adapterFilter.doPreFilter(adptGrpName, adptName, message, prop, request, response);
				}
			}
		}
		
		String preFiltersStr = prop.getProperty(PRE_FILTERS);
		if (StringUtils.isBlank(preFiltersStr)) {
			return message;
		}

		String[] preFilters = StringUtils.split(preFiltersStr, ",");
		for (String filterName : preFilters) {
			if (StringUtils.isBlank(filterName)) {
				continue;
			}

			HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(filterName.trim());
			if (adapterFilter != null) {
				message = adapterFilter.doPreFilter(adptGrpName, adptName, message, prop, request, response);
			} else {
				throw new Exception("Failed get Filter Class: " + filterName);
			}
		}
		return message;
	}

	private Object doPostFilters(String adptGrpName, String adptName, Object resultMessage, Properties prop,
			HttpServletRequest request, HttpServletResponse response) throws Exception {
		String postFiltersStr = prop.getProperty(POST_FILTERS);
		if (StringUtils.isBlank(postFiltersStr)) {
			return resultMessage;
		}

		String[] postFilters = StringUtils.split(postFiltersStr, ",");
		for (String filterName : postFilters) {
			if (StringUtils.isBlank(filterName)) {
				continue;
			}

			HttpAdapterFilter adapterFilter = HttpAdapterFilterFactory.createFilter(filterName.trim());
			if (adapterFilter != null) {
				resultMessage = adapterFilter.doPostFilter(adptGrpName, adptName, resultMessage, prop, request,
						response);
			} else {
				throw new Exception("Failed get Filter Class: " + filterName);
			}
		}
		return resultMessage;
	}

	public abstract void service(String adptGrpName, String adptName, HttpServletRequest request,
			HttpServletResponse response);
}
