package egovframework.com.ext.oauth.service;

import java.io.IOException;
import java.net.URI;
import java.util.Iterator;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.github.scribejava.core.builder.ScopeBuilder;
import com.github.scribejava.core.builder.ServiceBuilder;
import com.github.scribejava.core.model.OAuth2AccessToken;
import com.github.scribejava.core.model.OAuthRequest;
import com.github.scribejava.core.model.Response;
import com.github.scribejava.core.model.Verb;
import com.github.scribejava.core.oauth.OAuth20Service;

import nlib.cmm.snslogin.GoogleOAuthResponse;
import nlib.user.service.LoginService;
import nlib.util.StringUtil;


public class OAuthLogin {
	
	/** SNS 호출 시, URL callType 대체 문자열 */ 
	public static final String CALL_TYPE_LOGIN = "login";
	public static final String CALL_TYPE_MEMBER = "member";
	
	private OAuth20Service oauthService;
	private OAuthVO oauthVO;
	
	public OAuthLogin(OAuthVO oauthVO, String callType) {
		this(oauthVO, callType, null);
	}

	public OAuthLogin(OAuthVO oauthVO, String callType, String councilJsessionId) {
		
		if(oauthVO.getService().equals("google"))
		{
			ScopeBuilder scope = new ScopeBuilder();
			scope.withScope("profile");
			scope.withScope("openid");
			scope.withScope("email");
			//scope.withScope("https://www.googleapis.com/auth/user.phonenumbers.read");
			//scope.withScope("https://www.googleapis.com/auth/user.birthday.read");
			
			this.oauthService = new ServiceBuilder(oauthVO.getClientId())
					.apiSecret(oauthVO.getClientSecret())
					.callback(oauthVO.getRedirectUrl(callType, councilJsessionId))
					.defaultScope(scope)
					//.scope("profile")
					.build(oauthVO.getApi20Instance());
			
		} else if(oauthVO.getService().equals("kakao") || oauthVO.getService().equals("naver")) {
			
			this.oauthService = new ServiceBuilder(oauthVO.getClientId())
					.apiSecret(oauthVO.getClientSecret())
					.callback(oauthVO.getRedirectUrl(callType, councilJsessionId))
					//.scope("profile")
					.build(oauthVO.getApi20Instance());
		}
		
		this.oauthVO = oauthVO;
	}
	
	public String getOAuthURL(String state) {
		return this.oauthService.getAuthorizationUrl(state);
	}

	public OAuthUniversalUser getUserProfile(String code) throws Exception {
		
		OAuth2AccessToken accessToken = oauthService.getAccessToken(code);
		
		OAuthRequest request = new OAuthRequest(Verb.GET, this.oauthVO.getProfileUrl());
		oauthService.signRequest(accessToken, request);
		
		Response response = oauthService.execute(request);
		return parseJson(response.getBody());
	}

	private OAuthUniversalUser parseJson(String body) throws Exception {
		
		OAuthUniversalUser user = new OAuthUniversalUser();
		
		ObjectMapper mapper = new ObjectMapper();
		JsonNode rootNode = mapper.readTree(body);
		
		if (this.oauthVO.isNaver()) {
			//------------------------------------
			// 네이버 (2021.08.19 KKN) 
			//------------------------------------
			user.setSnsType(OAuthConfig.NAVER_SERVICE_NAME);
			JsonNode resNode = rootNode.get("response");
			
			// 사용자 내부 고유 ID (예: kh3lhfSg2v7TnJLmdhH7a0HyL-1zExIS4cF1mD4Hi4Y)
			user.setSnsId(resNode.get("id").asText());

			// 사용자로그인ID (메일형식) : 네이버 계정 제공하지 않으므로 연락처 이메일을 기본 메일 계정으로 설정 
			if (resNode.has("email")) {
				user.setSnsUserId(StringUtil.getString(resNode.get("email").asText(), ""));
				
				// 메일주소 
				user.setSnsEmail(StringUtil.getString(resNode.get("email").asText(), ""));
			}

			// 사용자명 (예: 홍길동) 
			if (resNode.has("name")) {
				user.setSnsName(StringUtil.getString(resNode.get("name").asText(), ""));
			}
			
			// 생년월일
			String birthday ="0000";
			String birthyear = "0000";
			if (resNode.has("birthday")) {
				birthday = StringUtil.getString(resNode.get("birthday").asText(), "0000");
			}
			if (resNode.has("birthyear")) {
				birthyear = StringUtil.getString(resNode.get("birthyear").asText(), "0000");
			}
			birthday = birthday.replaceAll("-", "");
			if(birthday.length() != 4) birthday = "0000";
			if(birthyear.length() != 4) birthyear = "0000";
			user.setSnsBirthday(birthyear + birthday);
			
			// 성별 
			if (resNode.has("gender")) {
				StringUtil.getString(resNode.get("gender").asText(), "");
			}
			// 로그인 성공
			user.setValidLogin(true);
			
		}
		else if (this.oauthVO.isGoogle()) {
			//------------------------------------
			// 구글  
			//------------------------------------
			user.setSnsType(OAuthConfig.GOOGLE_SERVICE_NAME);
			if (rootNode.has("sub")) 
				user.setSnsId(StringUtil.getString(rootNode.get("sub").asText(), ""));
			
			if (rootNode.has("email")) 
				user.setSnsUserId(StringUtil.getString(rootNode.get("email").asText(), ""));
			
			if (rootNode.has("name")) 
				user.setSnsName(StringUtil.getString(rootNode.get("name").asText(), ""));
			
		} 
		else if (this.oauthVO.isKakao()) {
			//------------------------------------
			// 카카오   
			//------------------------------------
			user.setSnsType(OAuthConfig.KAKAO_SERVICE_NAME);
			JsonNode resNode = rootNode.get("kakao_account");
			
			user.setSnsId((rootNode.get("id").asText() == null) ? "" : rootNode.get("id").asText());
			
			if (resNode.has("email")) {
				user.setSnsUserId(StringUtil.getString(resNode.get("email").asText(), ""));
				user.setSnsEmail(StringUtil.getString(resNode.get("email").asText(), ""));
			}
			if (resNode.has("gender")) 
			{
				user.setSnsGender(StringUtil.getString(resNode.get("gender").asText(), ""));
				if(user.getSnsGender().equals("male")) 
				{
					user.setSnsGender("M");
				}else if(user.getSnsGender().equals("female"))
				{
					user.setSnsGender("F");
				}
			}
			if (resNode.has("birthday") || resNode.has("birthyear")) 
				user.setSnsUserId((resNode.get("email").asText() == null) ? "" : resNode.get("email").asText());
			
			if (resNode.has("phone_number"))
				user.setSnsMobileNo(StringUtil.getString(resNode.get("phone_number").asText(), ""));
			
		}
		
		return user;
	}
	
	/**
	 * URL에 매개변수를 GET 방식으로 추가하여 리턴한다. 
	 * 
	 * @param url
	 * @param paramName
	 * @param paramValue
	 * @return
	 */
	public String appendUrlParam(String url, String paramName, String paramValue) {
		if(StringUtil.isEmpty(url)) return "";
		if(StringUtil.isEmpty(paramName)) return url;
		
		if(StringUtil.isEmpty(paramValue)) paramValue = "";
		
		if(url.contains("?")) url += "&";
		else url += "?";
		
		url += paramName + "=" + paramValue;
		
		return url;
	}
}
