package com.bb.service;

import java.net.SocketTimeoutException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.netty.channel.ConnectTimeoutException;
import io.netty.handler.timeout.ReadTimeoutException;
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.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
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 org.springframework.web.util.UriComponentsBuilder;

import com.bb.dao.CallBackDao;
import com.bb.dao.SiteDao;
import com.bb.model.Game;
import com.bb.model.NexusApiInfo;
import com.bb.model.VendorChangeBalanceLogVo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class NexusServiceImpl implements NexusService {

	/**
	 * Nexus 공통 API에 필요한 서비스
	 */
	
	@Autowired
	WebClient webClient;
	
	@Autowired
	private SiteDao siteDao;
	
	@Autowired
	CallBackDao callBackDao;
	
	private HttpHeaders getHeader(String LOG_PREFIX, NexusApiInfo apiInfo, String bodyJson) {
		LOG_PREFIX = LOG_PREFIX + "::getHeader::";
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
		headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
		headers.setAcceptCharset(Arrays.asList(Charset.forName("UTF-8")));
		
		String hashCode = getHashCode(LOG_PREFIX, bodyJson, apiInfo.getAgentSecretKey());
		headers.set("hash", hashCode);
		headers.set("agent", apiInfo.getAgentId());
		log.info(LOG_PREFIX+ "HttpHeaders::"+headers.toString());
		
		return headers;
	}
	
	
	private String getHashCode(String LOG_PREFIX, String body, String secretKey) {
		String hashCode = "";
		LOG_PREFIX = LOG_PREFIX + "::getHashCode::";
		try {
			// Json String Body + Secret Key
			String result = body + secretKey;
			// String result = "{\"username\":\"057007mptest01\",\"nickname\":\"007mptest01\",\"siteUsername\":\"057007mptest01\"}";
			log.info(LOG_PREFIX+ "Body + Secret Key::"+result);
			// SHA-256 Hash make
			MessageDigest digestObj = MessageDigest.getInstance("SHA-256");
			byte[] hash_data = digestObj.digest(result.getBytes("UTF-8"));
			
			// Base64 encoding
			hashCode = Base64.getEncoder().encodeToString(hash_data);
			log.info(LOG_PREFIX+ "hashCode::"+hashCode);
		} catch(Exception e) {
			log.error("#-NexusService::getHashCode::Exception::"+e.getMessage());
		}
		
		return hashCode;
	}
	

	@Override
	public List<Game> gameList(String LOG_PREFIX, NexusApiInfo apiInfo) {
		List<Game> gameList = null;
		LOG_PREFIX = LOG_PREFIX + "::gameList::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("vendorKey", apiInfo.getVendorKey());
			bodyObj.put("skin", apiInfo.getSkin());
			bodyObj.put("type", apiInfo.getType());
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/games");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("vendorKey", apiInfo.getVendorKey());
			params.add("skin", apiInfo.getSkin());
			params.add("type", apiInfo.getType());
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			JSONObject resObj = new JSONObject(response.getBody());
			if(resObj.getInt("code") == 0) {
				JSONArray games = resObj.getJSONArray("games");
				int length = games.length();
				gameList = new ArrayList<>();
				
				for(int i=0; i<length; i++) {
					Game game = new Game();
					JSONObject objGame = games.getJSONObject(i);
					JSONObject objName = objGame.getJSONObject("names");
					game.setGameIdx(objGame.getInt("row_num"));
					game.setGameKey(objGame.getString("key"));
					game.setGameName(objName.getString("ko"));
					game.setGameNameEn(objName.getString("en"));
					game.setGameImg(objGame.getString("image"));
					gameList.add(game);
				}
				
			} else {
				log.error(LOG_PREFIX+ "code::" + resObj.getString("code"));
				log.error(LOG_PREFIX+ "message::" + resObj.getString("msg"));
			}
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+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 JSONObject createUser(String LOG_PREFIX, NexusApiInfo apiInfo) {
		JSONObject jsonObj = null;
		LOG_PREFIX = LOG_PREFIX + "::createUser::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("username", apiInfo.getUsername());
			bodyObj.put("nickname", apiInfo.getNickname());
			bodyObj.put("siteUsername", apiInfo.getSiteUsername());
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/register");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getUsername());
			params.add("nickname", apiInfo.getNickname());
			params.add("siteUsername", apiInfo.getSiteUsername());
			log.info(LOG_PREFIX+ "entity::"+params.toString());
			log.info(LOG_PREFIX+ "headers::"+headers.toString());
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			log.info(LOG_PREFIX+ "Response::"+response.getBody().toString());
			jsonObj = new JSONObject(response.getBody());
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+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 jsonObj;
	}


	@Override
	public JSONObject userBalance(String LOG_PREFIX, NexusApiInfo apiInfo) {
		JSONObject jsonObj = null;
		LOG_PREFIX = LOG_PREFIX + "::userBalance::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("username", apiInfo.getUsername());
			bodyObj.put("siteUsername", apiInfo.getSiteUsername());
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/balance");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getUsername());
			params.add("siteUsername", apiInfo.getSiteUsername());
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+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 jsonObj;
	}


	@Override
	public JSONObject userDeposit(String LOG_PREFIX, NexusApiInfo apiInfo, int amount) {
		JSONObject jsonObj = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		long reqAtL = System.currentTimeMillis();
		String reqAt = sdf.format(reqAtL);
		LOG_PREFIX = LOG_PREFIX + "::userDeposit::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("username", apiInfo.getUsername());
			bodyObj.put("siteUsername", apiInfo.getSiteUsername());
			bodyObj.put("amount", amount);
			bodyObj.put("requestKey", Long.toString(reqAtL));
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/deposit");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getUsername());
			params.add("siteUsername", apiInfo.getSiteUsername());
			params.add("amount", amount);
			params.add("requestKey", Long.toString(reqAtL));
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
			if(jsonObj.getInt("code") == 0) {
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("nexus")
						.vendorApiId(apiInfo.getAgentId())
						.reqType("deposit")
						.amount(amount)
						.reqAt(reqAt)
						.reqStatus("SUCC")
						.reqMsg("code:"+jsonObj.getInt("code")+", message:"+jsonObj.getDouble("balance"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		} else {
    			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("nexus")
						.vendorApiId(apiInfo.getAgentId())
						.reqType("deposit")
						.amount(amount)
						.reqAt(reqAt)
						.reqStatus("FAIL")
						.reqMsg("code:"+jsonObj.getInt("code")+", message:"+jsonObj.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		}
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("deposit")
					.amount(amount)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg(e.getResponseBodyAsString())
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("deposit")
					.amount(amount)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("deposit")
					.amount(amount)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg("Exception e:"+e.getMessage())
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			e.printStackTrace();
        }
		
		return jsonObj;
	}


	@Override
	public JSONObject userWithdraw(String LOG_PREFIX, NexusApiInfo apiInfo, int amount) {
		JSONObject jsonObj = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		long reqAtL = System.currentTimeMillis();
		String reqAt = sdf.format(reqAtL);
		LOG_PREFIX = LOG_PREFIX + "::userWithdraw::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("username", apiInfo.getUsername());
			bodyObj.put("siteUsername", apiInfo.getSiteUsername());
			bodyObj.put("amount", amount);
			bodyObj.put("requestKey", Long.toString(reqAtL));
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/withdraw");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getUsername());
			params.add("siteUsername", apiInfo.getSiteUsername());
			params.add("amount", amount);
			params.add("requestKey", Long.toString(reqAtL));
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
			if(jsonObj.getInt("code") == 0) {
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("nexus")
						.vendorApiId(apiInfo.getAgentId())
						.reqType("withdraw")
						.amount(amount)
						.reqAt(reqAt)
						.reqStatus("SUCC")
						.reqMsg("code:"+jsonObj.getInt("code")+", message:"+jsonObj.getDouble("balance"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		} else {
    			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("nexus")
						.vendorApiId(apiInfo.getAgentId())
						.reqType("withdraw")
						.amount(amount)
						.reqAt(reqAt)
						.reqStatus("FAIL")
						.reqMsg("code:"+jsonObj.getInt("code")+", message:"+jsonObj.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		}
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("withdraw")
					.amount(amount)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg(e.getResponseBodyAsString())
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("withdraw")
					.amount(amount)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("withdraw")
					.amount(amount)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg("Exception e:"+e.getMessage())
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			e.printStackTrace();
        }
		
		return jsonObj;
	}


	@Override
	public JSONObject userWithdrawAll(String LOG_PREFIX, NexusApiInfo apiInfo) {
		JSONObject jsonObj = null;
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		long reqAtL = System.currentTimeMillis();
		String reqAt = sdf.format(reqAtL);
		LOG_PREFIX = LOG_PREFIX + "::userWithdrawAll::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("username", apiInfo.getUsername());
			bodyObj.put("siteUsername", apiInfo.getSiteUsername());
			bodyObj.put("amount", 0);
			bodyObj.put("requestKey", Long.toString(reqAtL));
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/withdraw");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getUsername());
			params.add("siteUsername", apiInfo.getSiteUsername());
			params.add("amount", 0);
			params.add("requestKey", Long.toString(reqAtL));
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
			if(jsonObj.getInt("code") == 0) {
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("nexus")
						.vendorApiId(apiInfo.getAgentId())
						.reqType("withdrawAll")
						.amount(0)
						.reqAt(reqAt)
						.reqStatus("SUCC")
						.reqMsg("code:"+jsonObj.getInt("code")+", message:"+jsonObj.getDouble("balance"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		} else {
    			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("nexus")
						.vendorApiId(apiInfo.getAgentId())
						.reqType("withdrawAll")
						.amount(0)
						.reqAt(reqAt)
						.reqStatus("FAIL")
						.reqMsg("code:"+jsonObj.getInt("code")+", message:"+jsonObj.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		}
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg(e.getResponseBodyAsString())
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("nexus")
					.vendorApiId(apiInfo.getAgentId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(reqAt)
					.reqStatus("FAIL")
					.reqMsg("Exception e:"+e.getMessage())
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			e.printStackTrace();
        }
		
		return jsonObj;
	}


	@Override
	public String gameStart(String LOG_PREFIX, NexusApiInfo apiInfo) {
		String luanchUrl = null;
		long reqAtL = System.currentTimeMillis();
		LOG_PREFIX = LOG_PREFIX + "::gameStart::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("vendorKey", apiInfo.getVendorKey());
			bodyObj.put("gameKey", apiInfo.getGameKey());
			bodyObj.put("siteUsername", apiInfo.getSiteUsername());
			bodyObj.put("nickname", apiInfo.getNickname());
			bodyObj.put("ip", apiInfo.getIp());
			bodyObj.put("language", apiInfo.getLanguage());
			bodyObj.put("platform", apiInfo.getPlatform());
			bodyObj.put("requestKey", Long.toString(reqAtL));
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/play");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("vendorKey", apiInfo.getVendorKey());
			params.add("gameKey", apiInfo.getGameKey());
			params.add("siteUsername", apiInfo.getSiteUsername());
			params.add("nickname", apiInfo.getNickname());
			params.add("ip", apiInfo.getIp());
			params.add("language", apiInfo.getLanguage());
			params.add("platform", apiInfo.getPlatform());
			params.add("requestKey", Long.toString(reqAtL));
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			JSONObject resObj = new JSONObject(response.getBody());
			if(resObj.getInt("code") == 0) {
				log.info(LOG_PREFIX+ "code::" + resObj.getInt("code"));
				log.info(LOG_PREFIX+ "url::" + resObj.getString("url"));
				log.info(LOG_PREFIX+ "userId::" + resObj.getInt("userId"));
				//log.info(LOG_PREFIX+ "balance::" + resObj.getInt("balance"));
				luanchUrl = resObj.getString("url");
			} else {
				
				
				try {
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", apiInfo.getSiteIdx());
					logParam.put("memberIdx", apiInfo.getMemberIdx());
					logParam.put("vendorIdx", apiInfo.getVendorKey());
					logParam.put("statusCode",resObj.getInt("code"));
					logParam.put("callBackType","LAUNCH");
					logParam.put("callBackReqBody",uriBuilder.toUriString());
					logParam.put("callBackResBody",resObj.getString("msg"));
					logParam.put("errorCode", "");
					logParam.put("errorMsg", "");
					logParam.put("regDate",System.currentTimeMillis());
					logParam.put("updDate",null);
					callBackDao.insertCallBackErrLog(logParam);
				}catch(Exception e) {
					
					
				}
				
				
				log.error(LOG_PREFIX+ "code::" + resObj.getInt("code"));
				log.error(LOG_PREFIX+ "message::" + resObj.getString("msg"));
			}
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "InterruptedException::"+rae.getMessage());
            }
            
            try {
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", apiInfo.getSiteIdx());
				logParam.put("memberIdx", apiInfo.getMemberIdx());
				logParam.put("vendorIdx", apiInfo.getVendorKey());
				logParam.put("statusCode",500);
				logParam.put("callBackType","LAUNCH");
				logParam.put("callBackReqBody",apiInfo.toString());
				logParam.put("callBackResBody",rae.getMessage());
				logParam.put("errorCode", "");
				logParam.put("errorMsg", "");
				logParam.put("regDate",System.currentTimeMillis());
				logParam.put("updDate",null);
				callBackDao.insertCallBackErrLog(logParam);
			}catch(Exception e) {
				
				
			}
            
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.getMessage());
			e.printStackTrace();
        }
		
		return luanchUrl;
	}


	@Override
	public JSONObject getDetail(String LOG_PREFIX, NexusApiInfo apiInfo, String trxId) {
		JSONObject jsonObj = null;
		LOG_PREFIX = LOG_PREFIX + "::getDetail::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("transactionKeys", trxId);
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/transaction/detail");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("transactionKeys", trxId);
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+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 jsonObj;
	}


	@Override
	public JSONObject getDetailUrl(String LOG_PREFIX, NexusApiInfo apiInfo, String trxId) {
		JSONObject jsonObj = null;
		LOG_PREFIX = LOG_PREFIX + "::getDetailUrl::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("transactionKey", trxId);
			bodyObj.put("lang", "ko");
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/getdetailurl");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("transactionKey", trxId);
			params.add("lang", "ko");
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+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 jsonObj;
	}


	@Override
	public JSONObject getTransaction(String LOG_PREFIX, NexusApiInfo apiInfo) {
		JSONObject jsonObj = null;
		LOG_PREFIX = LOG_PREFIX + "::getTransaction::";
		
		try {
			JSONObject bodyObj = new JSONObject();
			bodyObj.put("vendorKey", "evolution_casino");
			bodyObj.put("sdate", apiInfo.getSdate());
			bodyObj.put("edate", apiInfo.getEdate());
			bodyObj.put("username", apiInfo.getUsername());
			bodyObj.put("limit", apiInfo.getLimit());
			String bodyJson = bodyObj.toString();
			log.info(LOG_PREFIX+ "bodyJson::"+bodyJson);
			
			HttpHeaders headers = getHeader(LOG_PREFIX, apiInfo, bodyJson);
			UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/transaction");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("vendorKey", "evolution_casino");
			params.add("sdate", apiInfo.getSdate());
			params.add("edate", apiInfo.getEdate());
			params.add("username", apiInfo.getUsername());
			params.add("limit", apiInfo.getLimit());
			
			ResponseEntity<String> response = webClient.post()
					.uri(uriBuilder.toUriString())
					.headers(h -> h.addAll(headers))
					.bodyValue(params)
					.retrieve()
					.toEntity(String.class)
					.block();
			
			jsonObj = new JSONObject(response.getBody());
			
		} catch (WebClientResponseException e) {
			log.error(LOG_PREFIX+ "WebClientResponseException::"+e.getMessage());
			log.error(LOG_PREFIX+ "status code::"+e.getStatusCode().value());
			log.error(LOG_PREFIX+ "response body::"+e.getResponseBodyAsString());
		} catch (WebClientRequestException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "ConnectTimeoutException::"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof ReadTimeoutException) {
            	log.error(LOG_PREFIX+ "ReadTimeoutException::"+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 jsonObj;
	}
}
