
package com.openbanking.eai.common.token.client.impl;

import com.eactive.eai.common.property.PropManager;
import com.eactive.eai.common.util.Logger;
import com.eactive.eai.common.util.ScpDbAgentUtil;
import com.openbanking.eai.common.token.AccessTokenVO;
import com.openbanking.eai.common.token.OAuth2AccessTokenVO;
import com.openbanking.eai.common.token.client.HttpClientAccessTokenService;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpVersion;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang3.StringUtils;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Properties;


/** 
* 1. 기능 : HTTP 웹 컴포넌트를 POST 방식으로 호출할 수 있는 기능을 제공한다.
* 2. 처리 개요 : 
* *     - 2009.11.24 retry 로직 제거  : 요청
* 3. 주의사항 
*
* @author  : 
* @version : v 1.0.0
* @see : WLIAdapterFactory.java, WLIAdapter.java, WLIDefaultAdapter.java
* @since   : 

*/
public class HttpClientAccessTokenServiceForKFTC 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_CLIENT_ID        = "client_id";
	public static final String OAUTH_CLIENT_SECRET    = "client_secret";
	public static final String OAUTH_SCOPE            = "scope";
	public static final String OAUTH_GRANT_TYPE       = "grant_type";
	
    /** 
    * 1. 기능 : 결제원 오픈뱅킹 토큰 발급에 사용
    * 2. 처리 개요 : 
    *     - 속성 정보를 설정 하고 토큰 발급 URL 호출 한다.
    * 3. 주의사항 
    *
    * @param    prop    Http Adapter 속성 정보
    * @return   반환 된 AccessTokenVO
    * @exception    Exception 수동 시스템 간 통신 중 발생
    **/
    public AccessTokenVO execute(String name, Properties prop) throws Exception {
        
    	String url                   = prop.getProperty("URL");
    	String encode                = prop.getProperty("ENCODE");
    	String timeoutTemp           = prop.getProperty("HTTP_TIME_OUT", "0");
        String connectionTimeoutTemp = prop.getProperty("CONNECTION_TIMEOUT", "0");
        
//        // OAuth 정보 관리 대상을 어댑터의 프로퍼티로 변경
//        String oauthAccessTokenUrl   = prop.getProperty(AccessTokenVO.OAUTH_ACCESS_TOKEN_URL);
//        String oauthClientId         = prop.getProperty(AccessTokenVO.OAUTH_CLIENT_ID);
//        String oauthClientSecret     = prop.getProperty(AccessTokenVO.OAUTH_CLIENT_SECRET);
//        String oauthScope            = prop.getProperty(AccessTokenVO.OAUTH_SCOPE);
//        String oauthGrantType        = prop.getProperty(AccessTokenVO.OAUTH_GRANT_TYPE);
        
        int timeout                  = Integer.parseInt(timeoutTemp);
    	int connectionTimeout        = Integer.parseInt(connectionTimeoutTemp);
    	long currentTime             = System.currentTimeMillis();
    	
    	PropManager propManager = PropManager.getInstance();
    	String tokenInfo = propManager.getProperty(AccessTokenVO.PROP_GROUP, name);
    	
    	if (StringUtils.isBlank(tokenInfo)) {
    		throw new Exception("TokenInfo is NULL");
    	}
    	
    	/** 
    	 * 프로퍼티 OAuthInfo에 프로퍼티 명이 TokenManager에서 관리하는 Key(어댑터그룹명)로 등록
         * 		interval, url, client_id, client_secret(암호화), scope, grant_type
         * 
         * ex) _TST_OU_RST_SyC => {"interval":"86400","url":"oauth/2.0/token","client_id":"l7xx18ddb941fc0d4a6a910f5e132186aa88","client_secret":"18a91f9579994ce8ac10f1aab39ce205","scope":"sa","grant_type":"client_credentials"}
         */
		JSONObject tokenInfoObject = (JSONObject) JSONValue.parse(tokenInfo);
		
		String oauthAccessTokenUrl   = tokenInfoObject.containsKey(OAUTH_ACCESS_TOKEN_URI) ? (String)tokenInfoObject.get(OAUTH_ACCESS_TOKEN_URI) : "";
		String oauthClientId         = tokenInfoObject.containsKey(OAUTH_CLIENT_ID       ) ? (String)tokenInfoObject.get(OAUTH_CLIENT_ID       ) : "";
		String oauthClientSecret     = tokenInfoObject.containsKey(OAUTH_CLIENT_SECRET   ) ? (String)tokenInfoObject.get(OAUTH_CLIENT_SECRET   ) : "";
		String oauthScope            = tokenInfoObject.containsKey(OAUTH_SCOPE           ) ? (String)tokenInfoObject.get(OAUTH_SCOPE           ) : "";
		String oauthGrantType        = tokenInfoObject.containsKey(OAUTH_GRANT_TYPE      ) ? (String)tokenInfoObject.get(OAUTH_GRANT_TYPE      ) : "";
		
		//2020-03-12 Scp 모듈 Util로 변경
		// client_secret를 복호화한다
		try {
			oauthClientSecret = ScpDbAgentUtil.ScpDecB64(PropManager.getInstance().getProperties(ScpDbAgentUtil.EXT_MODULE), oauthClientSecret, "EUC-KR");
		} catch (Exception e) {
			logger.error("addInboundErrorInfo] scpdb_agent encryption Error - " + e.getMessage());
		}
		
		String uri         = url + "/" + oauthAccessTokenUrl;
		String contentType = propManager.getProperty(AccessTokenVO.PROP_GROUP, AccessTokenVO.HEADER_CONTENT_TYPE);
		
		HttpClient mclient = new HttpClient();
		PostMethod httpMethod = new PostMethod(uri);
		
		if(timeout > -1) {
			httpMethod.getParams().setSoTimeout(timeout);
	    }
	    
	    if ( connectionTimeout != 0) {
	    	httpMethod.getParams().setParameter("http.connection.timeout", connectionTimeout);
	    }
	    httpMethod.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_0);
		
		try {
			httpMethod.setParameter(OAUTH_CLIENT_ID    , oauthClientId    );
	        httpMethod.setParameter(OAUTH_CLIENT_SECRET, oauthClientSecret);
			httpMethod.setParameter(OAUTH_SCOPE        , oauthScope       );
			httpMethod.setParameter(OAUTH_GRANT_TYPE   , oauthGrantType   );
			
			httpMethod.setRequestHeader("Content-Type", contentType + "; charset=" + encode);
			
			logger.debug("HttpClientAccessTokenServiceKFTC] oauthClientId     = ["+ oauthClientId +"]");
			logger.debug("HttpClientAccessTokenServiceKFTC] oauthClientSecret = ["+ oauthClientSecret +"]");
			logger.debug("HttpClientAccessTokenServiceKFTC] oauthScope        = ["+ oauthScope +"]");
			logger.debug("HttpClientAccessTokenServiceKFTC] oauthGrantType    = ["+ oauthGrantType +"]");
			logger.debug("HttpClientAccessTokenServiceKFTC] contentType       = ["+ contentType +"]");
			logger.debug("HttpClientAccessTokenServiceKFTC] encode            = ["+ encode +"]");
			
	    	int status = mclient.executeMethod(httpMethod);
	    	
	    	if (status !=200) {
	    		throw new Exception ("oauth token receive status fail value= " + status);
	    	}
	    	
	    	byte[] responseBody = httpMethod.getResponseBody();
	    	String responseString = new String(responseBody, encode);
	    	
	    	OAuth2AccessTokenVO accessToken = new OAuth2AccessTokenVO();
	    	
	    	if (StringUtils.isNotBlank(responseString)) {
	    		logger.debug("HttpClientAccessTokenServiceKFTC] oauthToken RECV = ["+ responseString +"]");
	    		
	    		JSONObject responseJSON = (JSONObject) JSONValue.parse(responseString);
	    		
	    		if (responseJSON.containsKey("access_token")
	    				&& responseJSON.containsKey("token_type")     
	    				&& responseJSON.containsKey("expires_in")     
	    				&& responseJSON.containsKey("scope")) {
	    			accessToken.setAccessToken((String) responseJSON.get("access_token"));   
	    			accessToken.setTokenType  ((String) responseJSON.get("token_type"  ));     
	    			
	    			accessToken.setExpiration (new Date(currentTime +  ((BigDecimal)responseJSON.get("expires_in")).longValue()* 1000L));
//	    			accessToken.setExpiration (new Date(currentTime + ((long) responseJSON.get("expires_in") * 1000L)));     
	    			accessToken.setScope      ((String) responseJSON.get("scope"       ));          
	    		}
	    		
	    		if (responseJSON.containsKey("client_use_code")) {
	    			accessToken.setClientUseCode((String) responseJSON.get("client_use_code"));
	    		}
	    		
	    		logger.debug("HttpClientAccessTokenServiceKFTC] oauthToken ="+ accessToken.toString());
	    	} else {
	    		throw new Exception ("oauth token return null");
	    	}
	    	
	    	return accessToken;
	    // 오류 처리 상세화 필요	
		} catch (Exception e) {
			logger.error("HttpClientAccessTokenServiceKFTC] oauth token fail : " + e.toString() ,e);
			throw e;
		} finally {
			httpMethod.releaseConnection();
		}
    }
} 
