package com.bb.front;

import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.HashMap;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import jakarta.servlet.http.HttpServletRequest;

import org.apache.http.conn.ConnectTimeoutException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.ResourceAccessException;

import com.bb.service.AsyncSiteService;
import com.bb.service.CallBackService;
import com.bb.service.SiteService;

import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;

@Slf4j
@RequestMapping("/api/cb/pracp")
@RequiredArgsConstructor
@SecurityRequirement(name = "Authorization")
@EnableScheduling
@RestController
public class CallBackPracpController {

	@Autowired
	SiteService siteService;
	
	@Autowired
	CallBackService callBackService;
	
	@Autowired
	AsyncSiteService asyncCallBackService;
	
	
	@ResponseBody
	@GetMapping(value = "/{agentId}/balance")
	public ResponseEntity<net.sf.json.JSONObject> balance(HttpServletRequest request, @PathVariable String agentId, @RequestParam("player_code") String playerCode) throws Exception {
		JSONObject resData  = new JSONObject();
		JSONObject resultObj  = new JSONObject();
		HttpStatus httpStatus = HttpStatus.OK;
		
		HashMap<String, String> keyParam = new HashMap<>();
		keyParam.put("agentId", agentId);
		keyParam.put("vendorTitle", "pracp");
		HashMap<String, String> apiKeyInfo = siteService.getApiKeyInfo2(keyParam);
		
		String pracpUserId = decryptAES256(playerCode, apiKeyInfo.get("callbackPrivateKey"), apiKeyInfo.get("callbackPublicKey"));
		if(pracpUserId == null || "".equals(pracpUserId)) pracpUserId = playerCode;
		
		long siteIdx = Long.parseLong(pracpUserId.substring(0, 3), 16);
		String memberId = pracpUserId.substring(3, pracpUserId.length());
		final String LOG_PREFIX = "#-CB::PRACP::balance::"+memberId+":::";
		
		log.info(LOG_PREFIX+ "PathVariable::agentId::"+agentId);
		log.info(LOG_PREFIX+ "RequestParam::playerCode::"+playerCode);
		
		try {
			//사이트정보
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId",  memberId);
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			if(siteApiInfo == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
				resData.put("status", "FAIL");
				resultObj.put("balance", 0);
				resData.put("result", resultObj);
				return new ResponseEntity<JSONObject>(resData, httpStatus);
			}
			
			// ##--isTransfer 처리-##
			int balance = 0;
			if("N".equals(siteApiInfo.get("isTransfer").toString())) {
				log.info(LOG_PREFIX + "PLAY_SEAMLESS");
				org.codehaus.jettison.json.JSONObject member = new org.codehaus.jettison.json.JSONObject();
				member.put("userId", memberId);
				log.info(LOG_PREFIX+ "Callback URL::" + siteApiInfo.get("siteCbUrl")+"/balance");
				log.info(LOG_PREFIX+ "Callback Param::" + member.toString());
			
				member.put("userId", memberId);			
				org.codehaus.jettison.json.JSONObject resBalancedData = callBackService.getBalance(siteApiInfo, member);
				if(resBalancedData == null) {
					log.error(LOG_PREFIX+ "Error Msg: BALANCE_CALLBACK_ERROR");
					resData.put("status", "FAIL");
					resultObj.put("balance", 0);
					resData.put("result", resultObj);
					return new ResponseEntity<JSONObject>(resData, httpStatus);
				}
				balance = resBalancedData.getInt("balance");
			} else {
				log.info(LOG_PREFIX + "PLAY_TRANSFER");
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteIdx);
				balanceMap.put("memberId", memberId);
				balance = siteService.getUserBalance(balanceMap);
				
				if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
					org.codehaus.jettison.json.JSONObject member = new org.codehaus.jettison.json.JSONObject();
					member.put("userId", memberId);
					member.put("balance", balance);
					asyncCallBackService.asyncBalance(LOG_PREFIX, siteApiInfo, member);
				}
			}
			
			resData.put("status", "OK");
			resultObj.put("balance", balance);
			resData.put("result", resultObj);
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            
            log.error(LOG_PREFIX+ "[ResourceAccessException]"+rae.getMessage());
			
            resData.put("status", "FAIL");
			resultObj.put("balance", 0);
			resData.put("result", resultObj);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.getMessage());
			
			resData.put("status", "FAIL");
			resultObj.put("balance", 0);
			resData.put("result", resultObj);
		}
		
		ResponseEntity<JSONObject> res = new ResponseEntity<JSONObject>(resData, httpStatus);
		log.info(LOG_PREFIX+ "Response: "+resData.toString());
		
		return res;
	}
	
	@ResponseBody
	@PostMapping(value = "/{agentId}/transaction")
	public ResponseEntity<JSONObject> transaction(HttpServletRequest request, @PathVariable String agentId, @RequestBody JSONObject requestBody) throws Exception {
		ResponseEntity<JSONObject> resEntity = null;
		JSONObject resData  = new JSONObject();
		JSONObject resultObj  = new JSONObject();
		HttpStatus httpStatus = HttpStatus.OK;
		
		HashMap<String, String> keyParam = new HashMap<>();
		keyParam.put("agentId", agentId);
		keyParam.put("vendorTitle", "pracp");
		HashMap<String, String> apiKeyInfo = siteService.getApiKeyInfo2(keyParam);
		
		String playerCode = requestBody.getString("player_code");
		String pracpUserId = decryptAES256(playerCode, apiKeyInfo.get("callbackPrivateKey"), apiKeyInfo.get("callbackPublicKey"));
		if(pracpUserId == null || "".equals(pracpUserId)) pracpUserId = playerCode;
		
		long siteIdx = Long.parseLong(pracpUserId.substring(0, 3), 16);
		String memberId = pracpUserId.substring(3, pracpUserId.length());
		String transactionId = requestBody.getString("uuid");
		final String LOG_PREFIX = "#-CB::PRACP::transaction::"+memberId+"::"+transactionId+"::";
		log.info(LOG_PREFIX+ "Request::" + requestBody.toString());
		
		log.info(LOG_PREFIX+ "PathVariable::agentId::"+agentId);
		log.info(LOG_PREFIX+ "RequestParam::playerCode::"+playerCode);
		
		try {
			String transactionType = requestBody.getString("type");
			String vendorGameCode = requestBody.getString("provider_code");
			
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
			String betDateTimeStr = "";
			betDateTimeStr = sdf.format(System.currentTimeMillis());
			log.info(LOG_PREFIX+ "========== betDateTimeStr::" + betDateTimeStr);
			
			//사이트정보
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId", memberId);
			sParam.put("vendor", "pracp");
			sParam.put("vendorGameCode", vendorGameCode);
			log.info(LOG_PREFIX + "getSiteVendorInfo::"+sParam.toString());
			HashMap<String,String> siteVendorInfo = siteService.getSiteVendorInfo(sParam);
			if(siteVendorInfo == null) {
				log.error(LOG_PREFIX+ "존재하지 않는 회원입니다");
				resData.put("status", "FAIL");
				resultObj.put("balance", 0);
				resData.put("result", resultObj);
				resEntity = new ResponseEntity<JSONObject>(resData, httpStatus);
				return resEntity;
			}
			
			if(transactionType.equals("Bet")) {
				log.info(LOG_PREFIX+ "callBet() ================= type: "+transactionType);
				int amount = Math.abs(requestBody.getInt("amount"));
				resData = callBet(LOG_PREFIX, siteIdx, memberId, requestBody, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("Win")) {
				log.info(LOG_PREFIX+ "callWin() ================= type: "+transactionType);
				int amount = Math.abs(requestBody.getInt("amount"));
				resData = callWin(LOG_PREFIX, siteIdx, memberId, requestBody, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("Cancel")) {
				log.info(LOG_PREFIX+ "callCancel() ================= type: "+transactionType);
				int amount = 0;
				if(requestBody.has("amount")) {
					amount = requestBody.getInt("amount");
				}
				resData = callCancel(LOG_PREFIX, siteIdx, memberId, requestBody, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("Promo")) {
				log.info(LOG_PREFIX+ "callPromo() ================= type: "+transactionType);
				int amount = requestBody.getInt("amount");
				resData = callPromo(LOG_PREFIX, siteIdx, memberId, requestBody, betDateTimeStr, siteVendorInfo, amount);
				
			} else {
				log.error(LOG_PREFIX+ "unknown_transaction_type");
				resData.put("status", "FAIL");
				resultObj.put("balance", 0);
				resData.put("result", resultObj);
			}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            
            log.error(LOG_PREFIX+ "[ResourceAccessException]"+rae.getMessage());
			
            resData.put("status", "FAIL");
			resultObj.put("balance", 0);
			resData.put("result", resultObj);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.getMessage());
			
			resData.put("status", "FAIL");
			resultObj.put("balance", 0);
			resData.put("result", resultObj);
		}
		
		log.info(LOG_PREFIX+ "Response: "+resData.toString());
		resEntity = new ResponseEntity<JSONObject>(resData, httpStatus);
		
		return resEntity;
	}

	
	private JSONObject callBet(String LOG_PREFIX, long siteIdx, String memberId, JSONObject requestBody,
			String betDateTimeStr, HashMap<String, String> siteVendorInfo, int amount) {
		JSONObject response  = new JSONObject();
		JSONObject resultObj  = new JSONObject();
		
		try {
			// ##--isTransfer 처리-##
			final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
			
			String vendorTranKey = requestBody.getString("round_id");
			String tranId = requestBody.getString("uuid");
			String betId = requestBody.getString("refer_uuid");
			if(betId == null || "".equals(betId)) betId = tranId;
			
			String gameType = requestBody.getString("game_type").replaceAll(" ", "").toLowerCase();
			String gameId = requestBody.getString("game_code").replaceAll(" ", "").toLowerCase();
			
			String banGameType = siteVendorInfo.get("banGameType").toString().replaceAll(" ", "").toLowerCase();
			String banGameId = siteVendorInfo.get("banGameId").toString().replaceAll(" ", "").toLowerCase();
			
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			Long vendorIdx = Long.parseLong(siteVendorInfo.get("vendorIdx").toString());
			String gameName = requestBody.getString("game_name");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			LOG_PREFIX = LOG_PREFIX + "callBet:::";

			if(!"".equals(gameType) && !"".equals(banGameType) && banGameType.contains(gameType+"|")) {
				log.error(LOG_PREFIX+ "Ban Game Type : " + gameType);
				response.put("status", "FAIL");
				resultObj.put("balance", 0);
				response.put("result", resultObj);
				return response;
			}
			
			if(!"".equals(gameId) && !"".equals(banGameId) && banGameId.contains(gameId+"|")) {
				log.error(LOG_PREFIX+ "Ban Game Id : " + banGameId);
				response.put("status", "FAIL");
				resultObj.put("balance", 0);
				response.put("result", resultObj);
				return response;
			}
			
			if(siteVendorInfo.get("lastInVendorIdx")==null || "0".equals(siteVendorInfo.get("lastInVendorIdx").toString())) {
				HashMap memParam = new HashMap<>();
				memParam.put("siteIdx", siteIdx);
				memParam.put("memberIdx", memberIdx);
				memParam.put("lastInVendorIdx", Integer.parseInt(siteVendorInfo.get("vendorIdx").toString()));
				int updResult = siteService.updMemLastVendorIdx(memParam);
			} else {
				int lastInVendorIdx = Integer.parseInt(siteVendorInfo.get("lastInVendorIdx").toString());
				if(lastInVendorIdx != vendorIdx) {
					log.error(LOG_PREFIX+ "VendorIdx doesn't match");
					response.put("status", "FAIL");
					resultObj.put("balance", 0);
					response.put("result", resultObj);
					return response;
				}
			}
			
			long siteCredit = Long.parseLong(siteVendorInfo.get("credit").toString());
			// ##--isTransfer 처리-##
			if(siteCredit < amount && IS_TRANSFER.equals("N")) {
				log.error(LOG_PREFIX+ "NO_SITE_CREDIT");
				response.put("status", "FAIL");
				resultObj.put("balance", 0);
				response.put("result", resultObj);
				return response;
			}
			
			// 최대 베팅 금액 처리 (userMaxBet 우선 적용)
			long siteMaxBet = Long.parseLong(siteVendorInfo.get("siteMaxBet").toString());
			long userMaxBet = 0;
			if(siteVendorInfo.get("userMaxBet") != null && !siteVendorInfo.get("userMaxBet").toString().isEmpty()) {
				try {
					userMaxBet = Long.parseLong(siteVendorInfo.get("userMaxBet").toString());
				} catch (NumberFormatException e) {
					userMaxBet = 0;
				}
			}
			
			// 최종 maxBet 결정: userMaxBet이 0이면 siteMaxBet 사용, 0이 아니면 userMaxBet 사용
			long finalMaxBet = (userMaxBet > 0) ? userMaxBet : siteMaxBet;
			log.info(LOG_PREFIX+ "MaxBet Info - siteMaxBet: " + siteMaxBet + ", userMaxBet: " + userMaxBet + ", finalMaxBet: " + finalMaxBet);
			
			if(finalMaxBet < amount) {
				log.error(LOG_PREFIX+ "MAX_BET_AMOUNT_OVER");
				log.error(LOG_PREFIX+ "finalMaxBet : " + finalMaxBet +", amount : " + amount);
				response.put("status", "FAIL");
				resultObj.put("balance", 0);
				response.put("result", resultObj);
				return response;
			}

			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("Y")) {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(tranId);
				if(cntTr > 0) {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteIdx);
					balanceMap.put("memberId", memberId);
					int balance = siteService.getUserBalance(balanceMap);
					response.put("status", "BET_ALREADY_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return response;
				}
			}
			
			HashMap tranParam = new HashMap();
			tranParam.put("tranId", tranId);
			tranParam.put("refId",  betId);
			tranParam.put("siteIdx", siteIdx);
			tranParam.put("siteId", siteId);
			tranParam.put("memberIdx", memberIdx);
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", "SLOT");
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pracp");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameType", gameType);
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", gameName);
			tranParam.put("tranType", "debit");
			tranParam.put("depositAmt", amount);
			tranParam.put("creditAmt", "0");
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			org.codehaus.jettison.json.JSONObject callBackObj = new org.codehaus.jettison.json.JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "pracp");
			callBackObj.put("gameIdx", vendorIdx);
			callBackObj.put("gameKey", gameName);
			callBackObj.put("gameId", gameId);
			callBackObj.put("gameType", gameType);
			callBackObj.put("tranType", "debit");
			callBackObj.put("debit", amount);
			callBackObj.put("credit", 0);
			callBackObj.put("isCancel", 0);
			callBackObj.put("isBonus", 0);
			callBackObj.put("isData", "N");
			callBackObj.put("requestAt", betDateTimeStr);
			log.info(LOG_PREFIX + "SEND_BET request body: " + callBackObj.toString());
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("N")) {
				log.info(LOG_PREFIX + "PLAY_SEAMLESS");
				log.info(LOG_PREFIX + "-----INSERT_BET_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_BET_END-----");
				
				org.codehaus.jettison.json.JSONObject resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				log.info(LOG_PREFIX + "SEND_BET status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_BET response body: " + resData.toString());
				
				if(resData.getLong("result_code") == 0) {
					tranParam.put("balance", resData.getInt("balance"));
					tranParam.put("isTransfer", IS_TRANSFER);
					int res = siteService.updateCbApi(tranParam);
					log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
					
					int balance = resData.getInt("balance");
					response.put("status", "OK");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_ALREADY_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 80) {
					int balance = resData.getInt("balance");
					response.put("status", "INSUFFICIENT_FUNDS");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				response.put("status", "FAIL");
					resultObj.put("balance", 0);
					response.put("result", resultObj);
				}
			} else {
				log.info(LOG_PREFIX + "PLAY_TRANSFER");
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteIdx);
				balanceMap.put("memberId", memberId);
				int balance = siteService.getUserBalance(balanceMap);
				int afBalance = balance - amount;
				
				if(balance < amount) {
					response.put("status", "INSUFFICIENT_FUNDS");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "잔액부족::Response::" + response.toString());
					return response;
				}

				log.info(LOG_PREFIX + "-----INSERT_BET_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_BET_END-----");

				tranParam.put("balance", afBalance);
				tranParam.put("preBalance", balance);
				tranParam.put("isTransfer", IS_TRANSFER);
				int res = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
				
				response.put("status", "OK");
				resultObj.put("balance", afBalance);
				response.put("result", resultObj);
				
				if(siteVendorInfo.get("siteCbUrl") != null && !"".equals(siteVendorInfo.get("siteCbUrl").toString())) {
					callBackObj.put("balance", afBalance);
					asyncCallBackService.asyncChangeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				}
			}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            
            response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		}
		
		return response;
	}

	private JSONObject callWin(String LOG_PREFIX, long siteIdx, String memberId, JSONObject requestBody,
			String betDateTimeStr, HashMap<String, String> siteVendorInfo, int amount) {
		JSONObject response  = new JSONObject();
		JSONObject resultObj  = new JSONObject();
		
		try {
			// ##--isTransfer 처리-##
			final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
			
			String vendorTranKey = requestBody.getString("round_id");
			String tranId = requestBody.getString("uuid");
			String betId = requestBody.getString("refer_uuid");
			if(betId == null || "".equals(betId)) betId = tranId;
			
			String gameType = requestBody.getString("game_type").replaceAll(" ", "").toLowerCase();
			String gameId = requestBody.getString("game_code").replaceAll(" ", "").toLowerCase();
			
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			Long vendorIdx = Long.parseLong(siteVendorInfo.get("vendorIdx").toString());
			String gameName = requestBody.getString("game_name");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			LOG_PREFIX = LOG_PREFIX + "callWin:::";
			
			int siteMaxWin = Integer.parseInt(siteVendorInfo.get("siteMaxWin").toString());
			int overCreditAmt = 0;
			if(siteMaxWin < amount && siteMaxWin != 0) {
				log.error(LOG_PREFIX+ "MAX_WIN_AMOUNT_OVER");
				log.error(LOG_PREFIX+ "siteMaxWin : " + siteMaxWin +", amount : " + amount);
				overCreditAmt = amount - siteMaxWin;
				amount = siteMaxWin;
				log.error(LOG_PREFIX+ "Change amount : " + amount +", overCreditAmt : " + overCreditAmt);
			}
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("Y")) {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(tranId);
				if(cntTr > 0) {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteIdx);
					balanceMap.put("memberId", memberId);
					int balance = siteService.getUserBalance(balanceMap);
					response.put("status", "BET_ALREADY_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return response;
				}
				
				// 베팅 체크
				int cntBet = siteService.getBetIdCheck2(betId);
				if(cntBet == 0) {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteIdx);
					balanceMap.put("memberId", memberId);
					int balance = siteService.getUserBalance(balanceMap);
					response.put("status", "BET_DOES_NOT_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "NOT_FOUND_REF_DATA::Response::" + response.toString());
					return response;
				}
				
			}
			
			HashMap tranParam = new HashMap();
			tranParam.put("tranId", tranId);
			tranParam.put("refId",  betId);
			tranParam.put("siteIdx", siteIdx);
			tranParam.put("siteId", siteId);
			tranParam.put("memberIdx", memberIdx);
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", "SLOT");
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pracp");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameType", gameType);
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", gameName);
			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("overCreditAmt", overCreditAmt);
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			org.codehaus.jettison.json.JSONObject callBackObj = new org.codehaus.jettison.json.JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "pracp");
			callBackObj.put("gameIdx", vendorIdx);
			callBackObj.put("gameKey", gameName);
			callBackObj.put("gameId", gameId);
			callBackObj.put("gameType", gameType);
			callBackObj.put("tranType", "credit");
			callBackObj.put("debit", 0);
			callBackObj.put("credit", amount);
			callBackObj.put("isCancel", 0);
			callBackObj.put("isBonus", 0);
			callBackObj.put("isData", "N");
			callBackObj.put("requestAt", betDateTimeStr);
			log.info(LOG_PREFIX + "SEND_RESULT request body: " + callBackObj.toString());
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("N")) {
				log.info(LOG_PREFIX + "PLAY_SEAMLESS");
				log.info(LOG_PREFIX + "-----INSERT_RESULT_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_RESULT_END-----");

				org.codehaus.jettison.json.JSONObject resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				log.info(LOG_PREFIX + "SEND_RESULT status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_RESULT response body: " + resData.toString());
				
				if(resData.getLong("result_code") == 0) {
					tranParam.put("balance", resData.getInt("balance"));
					tranParam.put("isTransfer", IS_TRANSFER);
					int res = siteService.updateCbApi(tranParam);
					log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
					
					int balance = resData.getInt("balance");
					response.put("status", "OK");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_ALREADY_SETTLED");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 99) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_DOES_NOT_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				response.put("status", "FAIL");
					resultObj.put("balance", 0);
					response.put("result", resultObj);
				}
			} else {
				log.info(LOG_PREFIX + "PLAY_TRANSFER");
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteIdx);
				balanceMap.put("memberId", memberId);
				int balance = siteService.getUserBalance(balanceMap);
				int afBalance = balance + amount;

				log.info(LOG_PREFIX + "-----INSERT_RESULT_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_RESULT_END-----");

				tranParam.put("balance", afBalance);
				tranParam.put("preBalance", balance);
				tranParam.put("isTransfer", IS_TRANSFER);
				int res = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
				
				response.put("status", "OK");
				resultObj.put("balance", afBalance);
				response.put("result", resultObj);
				
				if(siteVendorInfo.get("siteCbUrl") != null && !"".equals(siteVendorInfo.get("siteCbUrl").toString())) {
					callBackObj.put("balance", afBalance);
					asyncCallBackService.asyncChangeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				}
			}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            
            response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		}
		
		return response;
	}

	private JSONObject callCancel(String LOG_PREFIX, long siteIdx, String memberId,
			JSONObject requestBody, String betDateTimeStr, HashMap<String, String> siteVendorInfo, int amount) {
		JSONObject response  = new JSONObject();
		JSONObject resultObj  = new JSONObject();
		
		try {
			// ##--isTransfer 처리-##
			final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
			
			String vendorTranKey = requestBody.getString("round_id");
			String tranId = requestBody.getString("uuid");

			String referUuid = requestBody.getString("refer_uuid");
			// 참조되는 트랜잭션 찾기
			HashMap<String, Object> refInfo = siteService.getRefBetInfoByTranId(referUuid);
			if(refInfo == null) {
				response.put("status", "BET_DOES_NOT_EXIST");
				resultObj.put("balance", 0);
				response.put("result", resultObj);
				return response;
			}
			
			String betId = refInfo.get("refId").toString();
			String referTranType = refInfo.get("tranType").toString();
			
			String gameType = requestBody.getString("game_type").replaceAll(" ", "").toLowerCase();
			String gameId = requestBody.getString("game_code").replaceAll(" ", "").toLowerCase();
			
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			Long vendorIdx = Long.parseLong(siteVendorInfo.get("vendorIdx").toString());
			String gameName = requestBody.getString("game_name");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			LOG_PREFIX = LOG_PREFIX + "callCancel:::";
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("Y")) {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(tranId);
				if(cntTr > 0) {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteIdx);
					balanceMap.put("memberId", memberId);
					int balance = siteService.getUserBalance(balanceMap);
					response.put("status", "BET_ALREADY_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return response;
				}
				
				// 베팅 체크
				int cntBet = siteService.getBetIdCheck2(betId);
				if(cntBet == 0) {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteIdx);
					balanceMap.put("memberId", memberId);
					int balance = siteService.getUserBalance(balanceMap);
					response.put("status", "BET_DOES_NOT_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "NOT_FOUND_REF_DATA::Response::" + response.toString());
					return response;
				}
			}
			
			HashMap tranParam = new HashMap();
			tranParam.put("tranId", tranId);
			tranParam.put("refId",  betId);
			tranParam.put("siteIdx", siteIdx);
			tranParam.put("siteId", siteId);
			tranParam.put("memberIdx", memberIdx);
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", "SLOT");
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pracp");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameType", gameType);
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", gameName);
			if(referTranType.equals("debit")) {
				// 배팅 취소
				tranParam.put("tranType", "credit");
				tranParam.put("depositAmt", "0");
				tranParam.put("creditAmt", Math.abs(amount));
			} else {
				// 당첨 취소
				tranParam.put("tranType", "debit");
				tranParam.put("depositAmt", Math.abs(amount));
				tranParam.put("creditAmt", "0");
			}
			tranParam.put("isCancel", "Y");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			org.codehaus.jettison.json.JSONObject callBackObj = new org.codehaus.jettison.json.JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "pracp");
			callBackObj.put("gameIdx", vendorIdx);
			callBackObj.put("gameKey", gameName);
			callBackObj.put("gameId", gameId);
			callBackObj.put("gameType", gameType);
			if(referTranType.equals("debit")) {
				// 배팅 취소
				callBackObj.put("tranType", "credit");
				callBackObj.put("debit", 0);
				callBackObj.put("credit", Math.abs(amount));
				callBackObj.put("isCancel", 1);
			} else {
				// 당첨 취소
				callBackObj.put("tranType", "adjust");
				callBackObj.put("debit", Math.abs(amount));
				callBackObj.put("credit", 0);
				callBackObj.put("isCancel", 0);
			}
			callBackObj.put("isBonus", 0);
			callBackObj.put("isData", "N");
			callBackObj.put("requestAt", betDateTimeStr);
			log.info(LOG_PREFIX + "SEND_CANCEL request body: " + callBackObj.toString());
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("N")) {
				log.info(LOG_PREFIX + "PLAY_SEAMLESS");
				log.info(LOG_PREFIX + "-----INSERT_CANCEL_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_CANCEL_END-----");
				
				org.codehaus.jettison.json.JSONObject resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				log.info(LOG_PREFIX + "SEND_CANCEL status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_CANCEL response body: " + resData.toString());
				
				if(resData.getLong("result_code") == 0) {
					tranParam.put("balance", resData.getInt("balance"));
					tranParam.put("isTransfer", IS_TRANSFER);
					int res = siteService.updateCbApi(tranParam);
					log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
					
					int balance = resData.getInt("balance");
					response.put("status", "OK");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_ALREADY_SETTLED");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 99) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_DOES_NOT_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				response.put("status", "FAIL");
					resultObj.put("balance", 0);
					response.put("result", resultObj);
				}
			} else {
				log.info(LOG_PREFIX + "PLAY_TRANSFER");
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteIdx);
				balanceMap.put("memberId", memberId);
				int balance = siteService.getUserBalance(balanceMap);
				int afBalance = 0;
				if(referTranType.equals("debit")) {
					// 배팅 취소
					afBalance = balance + Math.abs(amount);
				} else {
					// 당첨 취소
					afBalance = balance - Math.abs(amount);
				}
				
				log.info(LOG_PREFIX + "-----INSERT_CANCEL_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_CANCEL_END-----");

				tranParam.put("balance", afBalance);
				tranParam.put("preBalance", balance);
				tranParam.put("isTransfer", IS_TRANSFER);
				int res = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
				
				response.put("status", "OK");
				resultObj.put("balance", afBalance);
				response.put("result", resultObj);
				
				if(siteVendorInfo.get("siteCbUrl") != null && !"".equals(siteVendorInfo.get("siteCbUrl").toString())) {
					callBackObj.put("balance", afBalance);
					asyncCallBackService.asyncChangeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				}
			}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            
            response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		}
		
		return response;
	}

	private JSONObject callPromo(String LOG_PREFIX, long siteIdx, String memberId,
			JSONObject requestBody, String betDateTimeStr, HashMap<String, String> siteVendorInfo, int amount) {
		JSONObject response  = new JSONObject();
		JSONObject resultObj  = new JSONObject();

		try {
			// ##--isTransfer 처리-##
			final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();	
			
			String vendorTranKey = requestBody.getString("round_id");
			String tranId = requestBody.getString("uuid");
			String betId = requestBody.getString("refer_uuid");
			if(betId == null || "".equals(betId)) betId = tranId;
			
			String gameType = requestBody.getString("game_type").replaceAll(" ", "").toLowerCase();
			String gameId = requestBody.getString("game_code").replaceAll(" ", "").toLowerCase();
			
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			Long vendorIdx = Long.parseLong(siteVendorInfo.get("vendorIdx").toString());
			String gameName = requestBody.getString("game_name");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			LOG_PREFIX = LOG_PREFIX + "callPromo:::";
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("Y")) {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(tranId);
				if(cntTr > 0) {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteIdx);
					balanceMap.put("memberId", memberId);
					int balance = siteService.getUserBalance(balanceMap);
					response.put("status", "BET_ALREADY_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return response;
				}
			}
			
			HashMap tranParam = new HashMap();
			tranParam.put("tranId", tranId);
			tranParam.put("refId",  betId);
			tranParam.put("siteIdx", siteIdx);
			tranParam.put("siteId", siteId);
			tranParam.put("memberIdx", memberIdx);
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", "SLOT");
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pracp");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameType", gameType);
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", gameName);
			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			org.codehaus.jettison.json.JSONObject callBackObj = new org.codehaus.jettison.json.JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "pracp");
			callBackObj.put("gameIdx", vendorIdx);
			callBackObj.put("gameKey", gameName);
			callBackObj.put("gameId", gameId);
			callBackObj.put("gameType", gameType);
			callBackObj.put("tranType", "credit");
			callBackObj.put("debit", 0);
			callBackObj.put("credit", amount);
			callBackObj.put("isCancel", 0);
			callBackObj.put("isBonus", 1);
			callBackObj.put("isData", "N");
			callBackObj.put("requestAt", betDateTimeStr);
			log.info(LOG_PREFIX + "SEND_PROMO request body: " + callBackObj.toString());
			
			// ##--isTransfer 처리-##
			if(IS_TRANSFER.equals("N")) {
				log.info(LOG_PREFIX + "PLAY_SEAMLESS");
				log.info(LOG_PREFIX + "-----INSERT_PROMO_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_PROMO_END-----");
				
				org.codehaus.jettison.json.JSONObject resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				log.info(LOG_PREFIX + "SEND_PROMO status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_PROMO response body: " + resData.toString());
				
				if(resData.getLong("result_code") == 0) {
					tranParam.put("balance", resData.getInt("balance"));
					tranParam.put("isTransfer", IS_TRANSFER);
					int res = siteService.updateCbApi(tranParam);
					log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
					
					int balance = resData.getInt("balance");
					response.put("status", "OK");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_ALREADY_SETTLED");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else if(resData.getLong("result_code") == 99) {
					int balance = resData.getInt("balance");
					response.put("status", "BET_DOES_NOT_EXIST");
					resultObj.put("balance", balance);
					response.put("result", resultObj);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				response.put("status", "FAIL");
					resultObj.put("balance", 0);
					response.put("result", resultObj);
				}
			} else {
				log.info(LOG_PREFIX + "PLAY_TRANSFER");
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteIdx);
				balanceMap.put("memberId", memberId);
				int balance = siteService.getUserBalance(balanceMap);
				int afBalance = balance + amount;

				log.info(LOG_PREFIX + "-----INSERT_PROMO_START-----");
				siteService.commonBetinsert(tranParam);
				log.info(LOG_PREFIX + "-----INSERT_PROMO_END-----");
				
				tranParam.put("balance", afBalance);
				tranParam.put("preBalance", balance);
				tranParam.put("isTransfer", IS_TRANSFER);
				int res = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");
				
				response.put("status", "OK");
				resultObj.put("balance", afBalance);
				response.put("result", resultObj);
				
				if(siteVendorInfo.get("siteCbUrl") != null && !"".equals(siteVendorInfo.get("siteCbUrl").toString())) {
					callBackObj.put("balance", afBalance);
					asyncCallBackService.asyncChangeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				}
			}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            
            response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			response.put("status", "FAIL");
			resultObj.put("balance", 0);
			response.put("result", resultObj);
		}
		
		return response;
	}

	private static String decryptAES256(String encryptedData, String keyBase64, String ivBase64) {
        try {
            // JS의 encryptedData = encryptedData.split(" ").join("+")와 동일
            encryptedData = encryptedData.replace(" ", "+");

            System.out.println("[DECRYPT] Starting decryption process");
            System.out.println("[DECRYPT] Input data:");
            System.out.println("encryptedData = " + encryptedData);
            System.out.println("keyBase64 = " + keyBase64);
            System.out.println("ivBase64 = " + ivBase64);

            // Base64 → byte[]
            byte[] keyBytes = Base64.getDecoder().decode(keyBase64);
            byte[] ivBytes = Base64.getDecoder().decode(ivBase64);
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);

            System.out.println("[DECRYPT] Key and IV buffers created successfully");

            // Key, IV 설정
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);

            // Cipher 생성 (AES-256-CBC + PKCS5Padding)
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

            // 복호화
            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
            String decrypted = new String(decryptedBytes, StandardCharsets.UTF_8);

            System.out.println("[DECRYPT] Decryption successful");
            System.out.println("[DECRYPT] Decrypted result: " +
                    (decrypted.length() > 10 ? decrypted.substring(0, 10) + "..." : decrypted));

            return decrypted;

        } catch (Exception e) {
            System.err.println("[DECRYPT] Decryption failed with error: " + e.getMessage());
            return "";
        }
    }
}
