package com.style24.front.biz.thirdparty;

import com.gagaframework.web.parameter.GagaMap;
import com.gagaframework.web.util.GagaFileUtil;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.style24.core.support.env.TscConstants;
import com.style24.front.support.security.session.TsfSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import java.net.URI;


/**
 * 네이버 로그인
 *
 * @author jsshin
 * @since 2021. 02. 05
 */
@Component
@Slf4j
public class NaverLogin {

	@Autowired
	private Environment env;

	@Autowired
	private RestTemplate restTemplate;

	@Value("${has-ssl}")
	private String hasSsl;

	private String callBackUrl;
	private String clientId;
	private String clientSecret;
	private String profiles;
	private String tokenUrl;
	private String userInfoUrl;
	private String authorizeUrl;
	private String protocal;


	@PostConstruct
	public void init() {
		callBackUrl = env.getProperty("naver.login.callbackUrl");
		clientId = env.getProperty("naver.clientId");
		clientSecret = env.getProperty("naver.clientSecret");
		profiles = env.getProperty("spring.profiles.active").toLowerCase();
		tokenUrl = env.getProperty("naver.tokenUrl");
		userInfoUrl = env.getProperty("naver.userInfoUrl");
		authorizeUrl = env.getProperty("naver.authorizeUrl");

		boolean isSslServer = Boolean.parseBoolean(hasSsl);
		if (isSslServer) {
			protocal = "https://";
		} else {
			protocal = "http://";
		}

		log.debug("\n\n---- Naver initialization started ----");
		log.debug("callBackUrl: [{}]", callBackUrl);
		log.debug("clientId: [{}]", clientId);
		log.debug("clientSecret: [{}]", clientSecret);
		log.debug("profiles: [{}]", profiles);
		log.debug("tokenUrl: [{}]", tokenUrl);
		log.debug("userInfoUrl: [{}]", userInfoUrl);
		log.debug("authorizeUrl: [{}]", authorizeUrl);
		log.debug("\n--- Naver initialization completed ----\n");
	}

	public String getAuthorizeUrl(String state) {
		StringBuilder apiUrlBuilder = new StringBuilder();
		String redirectUri = GagaFileUtil.getConcatenationPath(protocal + TsfSession.getHttpServletRequest().getServerName(), callBackUrl);
		apiUrlBuilder.append(authorizeUrl)
				.append("?response_type=code&client_id=")
				.append(clientId)
				.append("&redirect_uri=")
				.append(redirectUri)
				.append("&state=")
				.append(state);

		log.info("apiUrlBuilder ===> {}", apiUrlBuilder.toString());
		return apiUrlBuilder.toString();
	}

	public GagaMap getAccessTocken(String code, String state) {
		GagaMap resultMap = new GagaMap();
		String requestGb = "";
		try {
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("grant_type", "authorization_code");
			params.add("client_id", clientId);
			params.add("client_secret", clientSecret);
			params.add("code", code);
			params.add("state", state);

			// state 값에 리다이렉트 url 같이 넘겨줌
			if (StringUtils.isNotBlank(state)) {
				String[] stateArr = StringUtils.split(state, "!@!");
				requestGb = stateArr[1];
			}

			// Header
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

			HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
			URI url = URI.create(tokenUrl);

			// POST방식으로 호출
			ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
			log.info("getAccessTocken responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());

			String jsonResult = responseEntity.getBody();
			log.info("getAccessTocken responseEntity.getBody(): {} ", jsonResult);

			Gson gson = new GsonBuilder().create();
			JsonObject obj = gson.fromJson(jsonResult, JsonObject.class);

			resultMap.setString("access_token", obj.get("access_token").toString());
			resultMap.setString("refresh_token", obj.get("refresh_token").toString());
			resultMap.setString("requestGb", requestGb);

		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return resultMap;
	}

	public GagaMap getNaverUserInfo(String accessToken) {
		GagaMap resultMap = new GagaMap();
		try {
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();

			// Header
			HttpHeaders headers = new HttpHeaders();
			headers.set("Authorization", "Bearer " + accessToken);
			headers.add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
			HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(params, headers);
			URI url = URI.create(userInfoUrl);

			// POST방식으로 호출
			ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);

			log.info("getNaverUserInfo responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());

			String jsonResult = responseEntity.getBody();
			log.info("getNaverUserInfo responseEntity.getBody(): {} ", jsonResult);

			Gson gson = new GsonBuilder().create();
			JsonObject obj = gson.fromJson(jsonResult, JsonObject.class);
			GagaMap response = gson.fromJson(obj.get("response"), GagaMap.class);

			String snsId = response.getString("id");
			String custNm = this.uniCodeDeCode(response.getString("name"));
			String email = response.getString("email");
			String cellphnno = response.getString("mobile");
			String birthYmd = response.getString("birthyear") + response.getString("birthday").replaceAll("-","");
			String sexGb = response.getString("gender").equals("M")? TscConstants.Gender.MALE.value() : TscConstants.Gender.FEMALE.value();
			String ci = this.requestReplace(response.getString("ci"),"encodeData");

			resultMap.setString("snsId", snsId);
			resultMap.setString("custNm", custNm);
			resultMap.setString("email", email);
			resultMap.setString("ci", ci);
			resultMap.setString("cellPhnno", cellphnno);
			resultMap.setString("birthYmd", birthYmd);
			resultMap.setString("sexGb", sexGb);

		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return resultMap;
	}

	public GagaMap getRefreshTocken(String refreshToken) {
		GagaMap resultMap = new GagaMap();
		try {
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("grant_type", "refresh_token");
			params.add("client_id", clientId);
			params.add("client_secret", clientSecret);
			params.add("refresh_token", refreshToken);

			// Header
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

			HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
			URI url = URI.create(tokenUrl);

			// POST방식으로 호출
			ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
			log.info("getRefreshTocken responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());

			String jsonResult = responseEntity.getBody();
			log.info("getRefreshTocken responseEntity.getBody(): {} ", jsonResult);

			Gson gson = new GsonBuilder().create();
			JsonObject obj =  gson.fromJson(jsonResult, JsonObject.class);

			resultMap.setString("access_token", obj.get("access_token").toString());

		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return resultMap;
	}

	public GagaMap saveUnlink(String accessToken) {
		GagaMap resultMap = new GagaMap();
		try {
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("grant_type", "delete");
			params.add("client_id", clientId);
			params.add("client_secret", clientSecret);
			params.add("access_token", accessToken);
			params.add("service_provider", "NAVER");

			// Header
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

			HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
			URI url = URI.create(tokenUrl);

			// POST방식으로 호출
			ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, request, String.class);
			log.info("saveUnlink : responseEntity.getStatusCode(): {} ", responseEntity.getStatusCode());

			String jsonResult = responseEntity.getBody();
			log.info("saveUnlink : responseEntity.getBody(): {} ", jsonResult);

			Gson gson = new GsonBuilder().create();
			JsonObject obj =  gson.fromJson(jsonResult, JsonObject.class);

			resultMap.setString("access_token", obj.get("access_token").toString());
			resultMap.setString("result", obj.get("result").toString());

		} catch (Exception e) {
			log.error(e.getMessage());
		}
		return resultMap;
	}

	public String requestReplace (String paramValue, String gubun) {

		String result = "";

		if (paramValue != null) {

			paramValue = paramValue.replaceAll("<", "&lt;").replaceAll(">", "&gt;");

			paramValue = paramValue.replaceAll("\\*", "");
			paramValue = paramValue.replaceAll("\\?", "");
			paramValue = paramValue.replaceAll("\\[", "");
			paramValue = paramValue.replaceAll("\\{", "");
			paramValue = paramValue.replaceAll("\\(", "");
			paramValue = paramValue.replaceAll("\\)", "");
			paramValue = paramValue.replaceAll("\\^", "");
			paramValue = paramValue.replaceAll("\\$", "");
			paramValue = paramValue.replaceAll("'", "");
			paramValue = paramValue.replaceAll("@", "");
			paramValue = paramValue.replaceAll("%", "");
			paramValue = paramValue.replaceAll(";", "");
			paramValue = paramValue.replaceAll(":", "");
			paramValue = paramValue.replaceAll("-", "");
			paramValue = paramValue.replaceAll("#", "");
			paramValue = paramValue.replaceAll("--", "");
			paramValue = paramValue.replaceAll("-", "");
			paramValue = paramValue.replaceAll(",", "");

			if(!"encodeData".equals(gubun)){
				paramValue = paramValue.replaceAll("\\+", "");
				paramValue = paramValue.replaceAll("/", "");
				paramValue = paramValue.replaceAll("=", "");
			}

			result = paramValue;

		}
		return result;
	}

	public String uniCodeDeCode(String unicode) {
		if (StringUtils.isBlank(unicode)) {
			return "";
		}

		StringBuffer str = new StringBuffer();
		char ch = 0;
		for( int i= unicode.indexOf("\\u"); i > -1; i = unicode.indexOf("\\u") ){
			ch = (char)Integer.parseInt( unicode.substring( i + 2, i + 6 ) ,16);
			str.append( unicode.substring(0, i) );
			str.append( String.valueOf(ch) );
			unicode = unicode.substring(i + 6);
		}
		str.append(unicode);

		return str.toString();
	}


}