package com.bb.service;
import java.util.Arrays;
import java.nio.charset.Charset;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import org.springframework.web.reactive.function.client.WebClientResponseException;

import com.bb.model.Game;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class PracpServiceImpl implements PracpService {
	
	@Autowired
	WebClient webClient;
	
	private String getAPI_KEY(String LOG_PREFIX, HashMap<String, String> apiInfo) {
		LOG_PREFIX = LOG_PREFIX + "::getAPI_KEY::";
		
		String apiKey = "";
		String apiAgentCode = apiInfo.get("apiAgentCode");
		String apiToken = apiInfo.get("apiToken");
		String timeStamp = apiInfo.get("timeStamp");
		
		log.info(LOG_PREFIX+ "apiAgentCode::"+apiAgentCode);
		log.info(LOG_PREFIX+ "apiToken::"+apiToken);
		log.info(LOG_PREFIX+ "timeStamp::"+timeStamp);
		
		String textA = apiAgentCode+apiToken+timeStamp;
		String salt = apiToken;
		String textB = textA+salt;
		log.info(LOG_PREFIX+ "textB::"+textB);
		
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-256");
		    md.update(textB.getBytes("UTF-8"));
		    byte[] digest = md.digest();
		    
		    StringBuilder sb = new StringBuilder();
		    for (byte b : digest) {
		        sb.append(String.format("%02x", b));  // 항상 2자리(앞에 0 포함)
		    }
		    
		    apiKey = sb.toString();
		    log.info(LOG_PREFIX+ "apiKey::"+apiKey);
		} catch(Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
		}
		
		return apiKey;
	}
	
	@Override
	public List<Game> getGameList(String LOG_PREFIX, HashMap<String, String> apiInfo) {
		LOG_PREFIX = LOG_PREFIX + "getGameList::";
		List<Game> gameList = null;
		
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
		headers.setAcceptCharset(Arrays.asList(Charset.forName("UTF-8")));
		
		String apiUrl = apiInfo.get("apiBaseUrl").toString() + "/app/game/list?";
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		long timeStampL = System.currentTimeMillis();
		String timeStamp = sdf.format(timeStampL);
		apiInfo.put("timeStamp", timeStamp);
		String apiKey = getAPI_KEY(LOG_PREFIX, apiInfo);
		String param = "api_key="+apiKey+"&timestamp="+timeStamp
			+"&agent_code="+apiInfo.get("apiAgentCode")+"&provider_code="+apiInfo.get("apiProviderCode");
		apiUrl = apiUrl + param;
		log.info(LOG_PREFIX+ "apiUrl::"+apiUrl);
		
		try {
			ResponseEntity<String> resEntity = webClient.get()
					.uri(apiUrl)
					.headers(h -> h.addAll(headers))
					.retrieve()
					.toEntity(String.class)
					.block();
			
			if(resEntity != null && resEntity.getStatusCode() == HttpStatus.OK) {
				JSONObject responseObj = new JSONObject(resEntity.getBody());
				//log.info(LOG_PREFIX+ "Response : " + responseObj.toString());
				
				JSONArray games = responseObj.getJSONArray("data");
				int length = games.length();
				gameList = new ArrayList<>();
				
				for(int i=0; i<length; i++) {
					Game game = new Game();
					JSONObject objGame = games.getJSONObject(i);
					String type = objGame.getString("type");
					
					if("slot".equals(type.toLowerCase())) {
						//log.info(objGame.toString());
						game.setGameIdx(i+1);
						game.setGameKey(objGame.getString("code"));
						game.setGameName(objGame.getString("name"));
						game.setGameNameEn(objGame.getString("en_name"));			
						game.setGameImg(objGame.getString("game_img"));
						gameList.add(game);
					}
				}
			}
		} catch (WebClientResponseException wce) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+wce.getMessage());
			log.error(LOG_PREFIX+ "status code::"+wce.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+wce.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof io.netty.channel.ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof io.netty.handler.timeout.ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "SocketTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			e.printStackTrace();
        }
		
		return gameList;
	}

	@Override
	public String getLaunchUrl(String LOG_PREFIX, HashMap<String, String> apiInfo) {
		LOG_PREFIX = LOG_PREFIX + "getLaunchUrl::";
		String luanchUrl = "";
		
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
		
		String apiUrl = apiInfo.get("apiBaseUrl").toString() + "/app/game/launch";
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		long timeStampL = System.currentTimeMillis();
		String timeStamp = sdf.format(timeStampL);
		apiInfo.put("timeStamp", timeStamp);
		String apiKey = getAPI_KEY(LOG_PREFIX, apiInfo);
		
		log.info(LOG_PREFIX+ "apiUrl::"+apiUrl);
		
		try {
			JSONObject params = new JSONObject();
			params.put("api_key", apiKey);
			params.put("timestamp", timeStamp);
			params.put("player_code", apiInfo.get("apiPlayerCode"));
			params.put("game_code", apiInfo.get("apiGameCode"));
			params.put("agent_code", apiInfo.get("apiAgentCode"));
			params.put("provider_code", apiInfo.get("apiProviderCode"));
			params.put("country_code", "KR");
			params.put("locale_code", "ko");
			log.info(LOG_PREFIX+ "params::"+params.toString());
			
			ResponseEntity<String> resEntity = webClient.post()
					.uri(apiUrl)
					.headers(h -> h.addAll(headers))
					.bodyValue(params.toString())
					.retrieve()
					.toEntity(String.class)
					.block();
			
			if(resEntity != null && resEntity.getStatusCode() == HttpStatus.OK) {
				JSONObject responseObj = new JSONObject(resEntity.getBody());
				log.info(LOG_PREFIX+ "Response : " + responseObj.toString());
				JSONObject dataObj = responseObj.getJSONObject("data");
				luanchUrl = dataObj.getString("game_url");
			}
		} catch (WebClientResponseException wce) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+wce.getMessage());
			log.error(LOG_PREFIX+ "status code::"+wce.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+wce.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof io.netty.channel.ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof io.netty.handler.timeout.ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "SocketTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			e.printStackTrace();
        }
		
		return luanchUrl;
	}

	@Override
	public JSONObject getDetail(String LOG_PREFIX, HashMap<String, String> apiInfo) {
		LOG_PREFIX = LOG_PREFIX + "getDetail::";
		JSONObject detailObj = null;
		
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
		
		String apiUrl = apiInfo.get("apiBaseUrl").toString() + "/app/game/detail-url?";
		
		SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
		long timeStampL = System.currentTimeMillis();
		String timeStamp = sdf.format(timeStampL);
		apiInfo.put("timeStamp", timeStamp);
		String apiKey = getAPI_KEY(LOG_PREFIX, apiInfo);
		String param = "api_key="+apiKey+"&timestamp="+timeStamp
			+"&agent_code="+apiInfo.get("apiAgentCode")+"&uuid="+apiInfo.get("uuid")+"&round_id="+apiInfo.get("round_id")+"&country_code=KR&locale_code=ko";
		apiUrl = apiUrl + param;
		log.info(LOG_PREFIX+ "apiUrl::"+apiUrl);
		
		try {
			ResponseEntity<String> resEntity = webClient.get()
					.uri(apiUrl)
					.headers(h -> h.addAll(headers))
					.retrieve()
					.toEntity(String.class)
					.block();
			
			if(resEntity != null && resEntity.getStatusCode() == HttpStatus.OK) {
				JSONObject responseObj = new JSONObject(resEntity.getBody());
				log.info(LOG_PREFIX+ "Response : " + responseObj.toString());
				
				detailObj = responseObj.getJSONObject("data");
			}
		} catch (WebClientResponseException wce) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+wce.getMessage());
			log.error(LOG_PREFIX+ "status code::"+wce.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+wce.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof io.netty.channel.ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof io.netty.handler.timeout.ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "SocketTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			e.printStackTrace();
        }
		
		return detailObj;
	}

}
