package com.openbanking.eai.common.token.servlet;

import com.eactive.eai.adapter.AdapterManager;
import com.eactive.eai.adapter.AdapterPropManager;
import com.eactive.eai.adapter.AdapterVO;
import com.eactive.eai.adapter.socket2.common.ExceptionStackTrace;
import com.eactive.eai.adapter.socket2.config.SocketAdapterManager;
import com.eactive.eai.adapter.socket2.config.SocketLoggerManager;
import com.eactive.eai.adapter.socket2.protocol.http.HttpServlet;
import com.eactive.eai.adapter.socket2.protocol.http.codec.HttpRequest;
import com.eactive.eai.adapter.socket2.protocol.http.codec.HttpResponse;
import com.eactive.eai.adapter.socket2.protocol.http.servlet.ThreadDumpUtil;
import com.eactive.eai.common.property.PropGroupVO;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;
import com.openbanking.eai.common.token.AccessTokenManager;
import com.openbanking.eai.common.token.AccessTokenVO;
import com.openbanking.eai.common.token.OAuth2AccessTokenVO;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import java.util.Properties;

public class AccessTokenServlet extends HttpServlet {
	final static SocketAdapterManager manager = SocketAdapterManager.getInstance();
    static Logger logger = SocketLoggerManager.getInstance().getLogger("FileLogger{NET}_HTTP");

	protected void doService(HttpRequest request, HttpResponse response) throws Exception {
		String command = request.getContext();
    	if (command.lastIndexOf('/') == -1) {
    		command = "";
    	} else {
    		command = command.substring(command.indexOf('/')+1);
    	}
		
    	String result = "";
    	
    	try {
    		String adapterGroupName = request.getParameter("adapter");
    		
    		if (command == null || "".equals(command) || "show".equals(command)) {
	    		result = show(adapterGroupName);
	    	} else if (command.startsWith("refresh")) {
	    		logger.fatal("AccessToken | " + adapterGroupName + " | refresh - " + request.getSession());
	    		result = refresh(adapterGroupName);
	    	} else if (command.startsWith("start")) {
	    		logger.fatal("AccessToken | " + adapterGroupName + " | start - " + request.getSession());
	    		result = start(adapterGroupName);
	    	} else if (command.startsWith("stop")) {
	    		logger.fatal("AccessToken | " + adapterGroupName + " | stop - " + request.getSession());
	    		result = stop(adapterGroupName);
	    	} else {
	    		response.setResponseCode(404);
	    		return;
	    	}
    		
		} catch(Throwable e) {
			result = "<pre>" + ExceptionStackTrace.dump(e) + "</pre>";
		}  	
		
		response.setContentType("text/html");
		response.setResponseCode(HttpResponse.HTTP_STATUS_SUCCESS);
		response.appendBody(result);
	}
	
	final static String SCRIPT =
			"	<script>                                                  \n" +
	        "		function toggle(){                                    \n" +
	        "			var obj = document.getElementsByName(\"action\"); \n" +
	        "			if (obj[0].style.display == \"block\"){           \n" +
	        "				for (var i=0; i<obj.length; i++ ) {           \n" +
	        "					obj[i].style.display=\"none\";            \n" +
	        "				}                                             \n" +
	        "			}else{                                            \n" +
	        "				for (var i=0; i<obj.length; i++ ) {           \n" +
	        "					obj[i].style.display=\"block\";           \n" +
	        "				}                                             \n" +
	        "			}                                                 \n" +
	        "		}                                                     \n" +
	        "	</script>                                                 \n";
	
	private String show(String adapterGroupName) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append(SCRIPT);
		
		AccessTokenManager manager = AccessTokenManager.getInstance();
		
//		HashMap<String, AccessTokenVO> tokens = manager.getAllAccessTokenVO();
//		for (String key : tokens.keySet()) {
		
		String adapterGroupNameList = manager.getTargetAdapterGroup();
    	String[] adapterGroupNames = adapterGroupNameList.split("[,]");
    	
    	ThreadGroup it = Thread.currentThread().getThreadGroup();
    	Thread[] threads = new Thread[it.activeCount()] ;
    	it.enumerate(threads);
    	
    	for (String key : adapterGroupNames) {
			if (adapterGroupName != null && !"".equals(adapterGroupName) && adapterGroupName.indexOf(key) < 0) {
				continue;
			}
			
			sb.append("¨Ó <b>" + key + "</b>");
			
			String status = manager.getStatus(key);
			
			if ("STARTED".equals(status)) {
	    		sb.append(" (" + status + ")");
	    	} else {
	    		sb.append(" <b>(" + status + ")</b>");
	    	}
			
			sb.append("<div name=\"action\" style=\"display:none\">");
			sb.append(" (<a href='/token/refresh?adapter=" + key + "'>refresh</a>");
	    	sb.append("|<a href='/token/start?adapter=" + key + "'>start</a>");
	    	sb.append("|<a href='/token/stop?adapter=" + key + "'>stop</a>)");
	    	sb.append("</div>");
	    	
	    	sb.append("\n");
	    	
	    	OAuth2AccessTokenVO token = (OAuth2AccessTokenVO) manager.getAccessTokenVO(key);
	    	
	    	if (token != null) {
	    		sb.append(String.format("%4s %-20s : %s\n", "", "access_token", token.getAccessToken()));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "expiration", token.getExpiration()));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "is_expired", token.isExpired()));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "scope", token.getScope()));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "token_type", token.getTokenType()));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "client_use_code", token.getClientUseCode()));
	    	}
	    	
	    	PropGroupVO vo = PropManager.getInstance().getPropGroupVO(AccessTokenVO.PROP_GROUP);
	    	String tokenInfo = vo.getProperty(key);
	    	
	    	if (tokenInfo != null) {
	    		sb.append("\n");
	    		
	    		JSONObject tokenInfoObject = (JSONObject) JSONValue.parse(tokenInfo);
	    		
	    		int interval = Integer.parseInt(tokenInfoObject.get("interval") != null ? (String) tokenInfoObject.get("interval") : "0");
	    		String hms = "sec";
	    		
	    		if (interval / 60 / 60 > 1) {
	    			interval = interval / 60 / 60;
		    		hms = "hour";
	    		} else if (interval / 60 > 1) {
	    			interval = interval / 60;
		    		hms = "min";
	    		}
	    		
	    		boolean adapter = false;
	    		String url = (String) tokenInfoObject.get("url");
	    		
	    		try {
		    		AdapterVO avo = (AdapterVO) AdapterManager.getInstance().getAdapterGroupVO(key).getAdapters().next();
		    		Properties properties = AdapterPropManager.getInstance().getProperties(avo.getPropGroupName());
		    		url = properties.getProperty("URL") + "/" + url;
		    		
		    		adapter = true;
	    		} catch (Exception ignore) {
	    			adapter = false;;
	    		}
	    		
	    		sb.append(String.format("%4s %-20s : %s\n", "", "adapter", adapter));
	    		sb.append(String.format("%4s %-20s : %s %s\n", "", "interval", interval, hms));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "url", url));
		    	sb.append(String.format("%4s %-20s : %s\n", "", "grant_type", (String) tokenInfoObject.get("grant_type")));
	    	}
	    	
		    /**
		     * threads info
		     */
	    	sb.append("\n<b>     threads</b>");
	    	sb.append("\n<font color='gray'>");
	    	sb.append("<table border='0' style='padding-left:25px'>");
	    	for (int i=0; i<threads.length; i++) {
	    		try {
		    		if ((threads[i] != null && threads[i].getName() != null && threads[i].getName().startsWith(key + "-AccessToken"))) {
		    			sb.append("<tr>");
						sb.append(ThreadDumpUtil.getStackTrace(threads[i]));
						sb.append("</tr>");
		    		}
	    		} catch(Exception e) {
	    			logger.error("Error", e) ;
	    		}
	    	}
	        sb.append("</table>");
		    sb.append("</font>");	    
		    sb.append("\n");
		    sb.append("\n");
	    	
//	    	String filter = key + "-AccessToken";
//	    	sb.append("<tr><td style='padding-left:20px; padding-bottom:20px'>");
//	    	sb.append(ThreadDumpUtil.dump(filter));
//	    	sb.append("</td></tr>");
		}
    	
    	sb.append("<span style=\"color:white\" ondblclick=\"toggle()\">button</span>");
    	
		return "<pre>" + sb.toString() + "</pre>";
	}
	
	private String refresh(String adapterGroupName) throws Exception {
		
		AccessTokenManager manager = AccessTokenManager.getInstance();
		
//		String token = manager.getAccessToken(adapterGroupName);
//		if (token == null)
//			return "<pre>token not exist</pre>";
		
		manager.refresh(adapterGroupName, true);
		
		return adapterGroupName + " | successfully refreshed";
	}
	
	private String start(String adapterGroupName) throws Exception {
		
		AccessTokenManager manager = AccessTokenManager.getInstance();
		manager.startToken(adapterGroupName);
		
		return adapterGroupName + " | successfully started";
	}
	
	private String stop(String adapterGroupName) throws Exception {
		
		AccessTokenManager manager = AccessTokenManager.getInstance();
		manager.stopToken(adapterGroupName);
		
		return adapterGroupName + " | successfully stoped";
	}
}