package com.eactive.eai.custom.token.client.impl;

import java.util.Properties;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import com.eactive.eai.adapter.http.secure.CustomHttpsSocketFactory;
import com.eactive.eai.adapter.http.secure.EasySSLProtocolSocketFactory;
import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;
import com.openbanking.eai.common.token.AccessTokenVO;
import com.openbanking.eai.common.token.OAuth2AccessTokenVO;
import com.openbanking.eai.common.token.client.HttpClientAccessTokenService;

public class HttpClientAccessTokenServiceForFinastra implements HttpClientAccessTokenService {
	public static Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);

	public static final String OAUTH_ACCESS_TOKEN_URI = "url";
	public static final String OAUTH_USER_NAME = "userName";
	public static final String OAUTH_PASSWORD = "password";

	@SuppressWarnings("deprecation")
	public AccessTokenVO execute(String name, Properties prop) throws Exception {
		String url = prop.getProperty("URL");
		String timeoutTemp = prop.getProperty("HTTP_TIME_OUT", "30");
		String connectionTimeoutTemp = prop.getProperty("CONNECTION_TIMEOUT", "30");
		String httpVersion = prop.getProperty("HTTP_VERSION", "HTTP_1_0");

		int timeout = Integer.parseInt(timeoutTemp);
		int connectionTimeout = Integer.parseInt(connectionTimeoutTemp);

		PropManager propManager = PropManager.getInstance();
		String oAuthInfo = propManager.getProperty(AccessTokenVO.PROP_GROUP, name);

		if (StringUtils.isBlank(oAuthInfo)) {
			throw new Exception("oAuthInfo is NULL");
		}

		/** 
    	 * @formatter:off
    	 * 프로퍼티 OAuthInfo에 프로퍼티 명이 TokenManager에서 관리하는 Key(어댑터그룹명)로 등록
         * ex) _TST_OU_RST_SyC =>
         * {
         *    "url": "MisysSSOFBPService/SSOloginService",
         *    "userName": "interfaceuser",
         *    "password": "interfaceuser"
         * }
         * @formatter:on
         */
		JSONObject oauthInfoObject = (JSONObject) JSONValue.parseWithException(oAuthInfo);

		String oauthAccessTokenUrl = oauthInfoObject.containsKey(OAUTH_ACCESS_TOKEN_URI)
				? (String) oauthInfoObject.get(OAUTH_ACCESS_TOKEN_URI)
				: "";
		String oauthUserName = oauthInfoObject.containsKey(OAUTH_USER_NAME)
				? (String) oauthInfoObject.get(OAUTH_USER_NAME)
				: "";
		String oauthPassword = oauthInfoObject.containsKey(OAUTH_PASSWORD)
				? (String) oauthInfoObject.get(OAUTH_USER_NAME)
				: "";

		String uri = "";
		if (StringUtils.contains(oauthAccessTokenUrl, "http://")
				|| StringUtils.contains(oauthAccessTokenUrl, "https://")) {
			uri = oauthAccessTokenUrl;
		} else {
			uri = url + "/" + oauthAccessTokenUrl;
		}

		HttpClient mclient = new HttpClient();
		PostMethod httpMethod = new PostMethod(uri);

		if (timeout > -1) {
			mclient.getHttpConnectionManager().getParams().setSoTimeout(timeout);
		}

		if (connectionTimeout != 0) {
			mclient.getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout);
		}

		if (StringUtils.equals(httpVersion, "HTTP_1_1")) {
			httpMethod.setRequestHeader("Connection", "close");
			httpMethod.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_1);
		} else {
			httpMethod.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_0);
		}

		if (uri != null && uri.startsWith("https")) {
			Protocol.registerProtocol("https",
					new Protocol("https", new CustomHttpsSocketFactory(new EasySSLProtocolSocketFactory()), 443));
		}

		try {
			String bodyMsg = String.format("{\"userName\" : \"%s\",\"password\" : \"%s\"}", oauthUserName,
					oauthPassword);
			httpMethod.setRequestBody(bodyMsg);
			httpMethod.setRequestHeader("Content-Type", "application/json");

			if (logger.isDebug()) {
				logger.debug("HttpClientAccessTokenServiceForFinastra] tokenUrl      = [" + uri + "]");
				logger.debug("HttpClientAccessTokenServiceForFinastra] oauthUserName = [" + oauthUserName + "]");
				logger.debug("HttpClientAccessTokenServiceForFinastra] oauthPassword = [" + oauthPassword + "]");
				logger.debug("HttpClientAccessTokenServiceForFinastra] bodyMsg       = [" + bodyMsg + "]");
			}

			int status = mclient.executeMethod(httpMethod);

			if (status != 200) {
				if (status >= 400 && status < 500) {
					logger.error(new String(httpMethod.getResponseBody()));
				}
				throw new Exception("oauth token receive status fail value= " + status);
			}

			byte[] responseBody = httpMethod.getResponseBody();
			String responseString = new String(responseBody);

			OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO();

			if (StringUtils.isNotBlank(responseString)) {
				if (logger.isDebug()) {
					logger.debug("HttpClientAccessTokenServiceForFinastra] oauthToken RECV = [" + responseString + "]");
				}

				JSONObject responseJSON = (JSONObject) JSONValue.parse(responseString);

				if (responseJSON.containsKey("result")) {
					accessToken.setAccessToken((String) responseJSON.get("result"));
					accessToken.setTokenType("bearer");
				}

				if (logger.isDebug()) {
					logger.debug("HttpClientAccessTokenServiceForFinastra] oauthToken =" + accessToken.toString());
				}
			} else {
				throw new Exception("oauth token return null");
			}

			return accessToken;
		} catch (Exception e) {
			logger.error("HttpClientAccessTokenServiceForFinastra] oauth token fail : " + e.toString(), e);
			throw e;
		} finally {
			httpMethod.releaseConnection();
		}
	}
}