package com.bb.front;

import java.net.SocketTimeoutException;
import java.util.HashMap;

import jakarta.servlet.http.HttpServletRequest;

import org.apache.http.conn.ConnectTimeoutException;
import org.codehaus.jettison.json.JSONObject;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.ResourceAccessException;

import com.bb.model.SvendorResponse;
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;

@Slf4j
@RequestMapping("/api/callback/pink")
@RequiredArgsConstructor
@SecurityRequirement(name = "Authorization")
@EnableScheduling
@RestController
public class CallbackPinkController {

	@Autowired
	SiteService siteService;
	
	@Autowired
	CallBackService callBackService;
	
	@Autowired
	AsyncSiteService asyncCallBackService;
	
	
	@ResponseBody
	@PostMapping(path = "/balance")
	public ResponseEntity<SvendorResponse> balance(HttpServletRequest request, @RequestBody net.sf.json.JSONObject requestBody) throws Exception {
		
		SvendorResponse response = new SvendorResponse();
		String vendorUsername = requestBody.getString("userid");
		String uuid = vendorUsername;
		
		//사이트정보
		HashMap siteApiInfo = siteService.getNewSiteApiInfo(vendorUsername);
		long siteIdx = 0L;
		String memberId = "";
		if(siteApiInfo != null) {
			siteIdx = Long.parseLong(siteApiInfo.get("siteIdx").toString());
			memberId = siteApiInfo.get("memberId").toString();
		} else {
			siteIdx = Long.parseLong(vendorUsername.substring(0, 3), 16);
			memberId = vendorUsername.substring(3, vendorUsername.length());
			
			//사이트정보
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId",  memberId);
			siteApiInfo = siteService.getSiteApiInfo(sParam);
		}
		
		final String LOG_PREFIX = "#-CB::PINK::"+memberId+"::balance:::";
		log.info(LOG_PREFIX+ "Request Body::" + requestBody.toString());
		
		try {
			if(siteApiInfo == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
				response.setBalance("0");
				response.setId(uuid);
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			if(siteApiInfo.get("memberIdx") == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_USER");
				response.setBalance("0");
				response.setId(uuid);
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			// ##--isTransfer 처리-##
			int balance = 0;
			if("N".equals(siteApiInfo.get("isTransfer").toString())) {
				log.info(LOG_PREFIX + "PLAY_SEAMLESS");
				JSONObject member = new JSONObject();
				member.put("userId", memberId);
				log.info(LOG_PREFIX+ "balance Req ::"+ member.toString());
				JSONObject resData  = callBackService.getBalance(siteApiInfo, member);
				if(resData == null) {
					log.error(LOG_PREFIX+ "Error Msg: BALANCE_CALLBACK_ERROR");
					response.setBalance("0");
					response.setId(uuid);
					log.info(LOG_PREFIX+ "Response::"+response.toString());
					return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
				}
				log.info(LOG_PREFIX+ "balance Res ::"+ resData.toString());
				balance = resData.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())) {
					JSONObject member = new JSONObject();
					member.put("userId", memberId);
					member.put("balance", balance);
					asyncCallBackService.asyncBalance(LOG_PREFIX, siteApiInfo, member);
				}
			}
			
			response.setBalance(Integer.toString(balance));
			response.setId(uuid);
			
		} 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+ "Error Msg: RESOURCE_ACCESS_ERROR");
            response.setBalance("0");
			response.setId(uuid);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			
			log.error(LOG_PREFIX+ "Error Msg: UNKNOWN_SERVER_ERROR");
			response.setBalance("0");
			response.setId(uuid);
		}
		
		log.info(LOG_PREFIX+ "Response::"+response.toString());
		return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
	}
	
	
	@ResponseBody
	@PostMapping(path = "/bet")
	public ResponseEntity<SvendorResponse> callBet(HttpServletRequest request, @RequestBody net.sf.json.JSONObject requestBody) throws Exception {
		
		SvendorResponse response = new SvendorResponse();
		String vendorUsername = requestBody.getString("userid");
		String uuid = vendorUsername;
		String vendorGameCode = requestBody.getString("vendor");
		
		//사이트정보
		HashMap sParam = new HashMap<>();
		sParam.put("vendorUsername", vendorUsername);
		sParam.put("vendor", "pink");
		sParam.put("vendorGameCode", vendorGameCode);
		HashMap siteVendorInfo = siteService.getNewSiteVendorInfo(sParam);
		long siteIdx = 0L;
		String memberId = "";
		if(siteVendorInfo != null) {
			siteIdx = Long.parseLong(siteVendorInfo.get("siteIdx").toString());
			memberId = siteVendorInfo.get("memberId").toString();
		} else {
			siteIdx = Long.parseLong(vendorUsername.substring(0, 3), 16);
			memberId = vendorUsername.substring(3, vendorUsername.length());
			
			//사이트정보
			sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId", memberId);
			sParam.put("vendor", "pink");
			sParam.put("vendorGameCode", vendorGameCode);
			siteVendorInfo = siteService.getSiteVendorInfo(sParam);
		}
		
		final String LOG_PREFIX = "#-CB::PINK::"+memberId+"::BET::"+requestBody.getString("tr_id")+":::";
		log.info(LOG_PREFIX+ "Request Body::" + requestBody.toString());
		
		if(siteVendorInfo == null) {
			log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
			response.setBalance("0");
			response.setId(uuid);
			response.setStatuscode(1);
			response.setStatus("NOT_FOUND_SITE_INFO");
			log.info(LOG_PREFIX+ "Response::"+response.toString());
			return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
		}
		
		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		// 배팅 고유ID
		String transactionId = requestBody.getString("tr_id");
		log.info(LOG_PREFIX+ "transactionId::"+transactionId);
		// 베팅 참조ID
		String referenceId = requestBody.getString("ref_id");
		log.info(LOG_PREFIX+ "referenceId"+referenceId);
		// 라운드 고유ID
		String roundId = requestBody.getString("round");
		log.info(LOG_PREFIX+ "roundId::"+roundId);
		String tranId = transactionId;
		//String betId = referenceId;
		String betId = roundId+"#"+vendorUsername;
		// 베팅 시각
		String betDateTimeStr = requestBody.getString("processed_at");
		
		// 게임타입
		String gameType = requestBody.getString("game_type").replaceAll(" ", "").toLowerCase();
		// 게임테이블 아이디 (optional)
		String gameId = "";
		if(requestBody.has("game_code")) gameId = requestBody.getString("game_code");
		String targetTableId = gameId.replaceAll(" ", "").toLowerCase();
		String gameName = "";
		if(requestBody.has("title")) gameName = requestBody.getString("title");
		// 배팅액
		String amountS = requestBody.getString("amount");
		int amount = 0;
		Double amountD = Double.parseDouble(amountS); 
		amount = amountD.intValue();
		
		try {
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			int vendorIdx = Integer.parseInt(siteVendorInfo.get("vendorIdx").toString());
			String vendorCetegory = siteVendorInfo.get("vendorCetegory").toString();
			
			String banGameType = siteVendorInfo.get("banGameType").toString().replaceAll(" ", "").toLowerCase();
			String banGameId = siteVendorInfo.get("banGameId").toString().replaceAll(" ", "").toLowerCase();
			
			if(!"".equals(gameType) && !"".equals(banGameType) && banGameType.contains(gameType+"|")) {
				// Ban Game Type Exception
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteIdx);
				logParam.put("memberIdx", memberIdx);
				logParam.put("vendorIdx", vendorIdx);
				logParam.put("statusCode", 501L);
				logParam.put("callBackType", "debit");
				logParam.put("tranId", tranId);
				logParam.put("callBackReqBody", "gameType:"+gameType+"이 블락설정");
				logParam.put("callBackResBody", "");
				logParam.put("errorCode", "BLOCK_GAME_TYPE");
				logParam.put("errorMsg", "gameType:"+gameType+"이 블락설정");
				long startTimestamp = System.currentTimeMillis();
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", startTimestamp);
				callBackService.insertCallBackErrLog(logParam);
				log.error(LOG_PREFIX+ "Ban Game Type : " + gameType);
				
				response.setBalance("0");
				response.setId(uuid);
				response.setStatuscode(1);
				response.setStatus("BAN_GAME_TYPE_" + gameType);
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			if(!"".equals(targetTableId) && !"".equals(banGameId) && banGameId.contains(targetTableId+"|")) {
				// Ban Game Id Exception
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteIdx);
				logParam.put("memberIdx", memberIdx);
				logParam.put("vendorIdx", vendorIdx);
				logParam.put("statusCode", 502L);
				logParam.put("callBackType", "debit");
				logParam.put("tranId", tranId);
				logParam.put("callBackReqBody", "gameId:"+gameId+"("+gameName+")이 블락설정");
				logParam.put("callBackResBody", "");
				logParam.put("errorCode", "BLOCK_GAME_ID");
				logParam.put("errorMsg", "gameId:"+gameId+"("+gameName+")이 블락설정");
				long startTimestamp = System.currentTimeMillis();
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", startTimestamp);
				callBackService.insertCallBackErrLog(logParam);
				log.error(LOG_PREFIX+ "Ban Game Id : " + gameId);
				
				response.setBalance("0");
				response.setId(uuid);
				response.setStatuscode(1);
				response.setStatus("BAN_GAME_ID_" + gameId);
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			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.setBalance("0");
					response.setId(uuid);
					response.setStatuscode(1);
					response.setStatus("ACCESS_VENDOR_MISSMATCH_"+lastInVendorIdx);
					log.info(LOG_PREFIX+ "Response::"+response.toString());
					return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
				}
			}
			
			long siteCredit = Long.parseLong(siteVendorInfo.get("credit").toString());
			// ##--isTransfer 처리-##
			if(siteCredit < amount && IS_TRANSFER.equals("N")) {
				log.error(LOG_PREFIX+ "NO_SITE_CREDIT");
				response.setBalance("0");
				response.setId(uuid);
				response.setStatuscode(1);
				response.setStatus("NO_SITE_CREDIT");
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			long siteMaxBet = Long.parseLong(siteVendorInfo.get("siteMaxBet").toString());
			if(siteMaxBet < amount) {
				log.error(LOG_PREFIX+ "MAX_BET_AMOUNT_OVER");
				log.error(LOG_PREFIX+ "siteMaxBet : " + siteMaxBet +", amount : " + amount);
				response.setBalance("0");
				response.setId(uuid);
				response.setStatuscode(1);
				response.setStatus("MAX_BET_AMOUNT_OVER");
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			// ##--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.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
				}
			}
			
			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", vendorCetegory);
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pink");
			tranParam.put("vendorTranKey", referenceId);
			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);
			
			JSONObject callBackObj = new JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("betKey", referenceId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "pink");
			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("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-----");
				
				JSONObject resData = null;
				if(vendorCetegory.equals("SLOT")) {
					resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				} else {
					resData = callBackService.changeBalance(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.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
				} else if(resData.getLong("result_code") == 98) {
					// 중복
					int balance = resData.getInt("balance");
					response.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
				} else if(resData.getLong("result_code") == 80) {
					// 중복
					int balance = resData.getInt("balance");
					response.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
				} else {
					// 실패
					log.error(LOG_PREFIX+ "CALLBACK_ERROR");
					response.setBalance("0");
					response.setId(uuid);
					response.setStatuscode(1);
					response.setStatus("CALLBACK_ERROR");
				}
			} 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.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
					log.error(LOG_PREFIX+ "잔액부족::Response::" + response.toString());
					return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
				}
				
				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.setBalance(Integer.toString(afBalance));
				response.setId(uuid);
				response.setStatuscode(0);
				response.setStatus("OK");
				
				if(siteVendorInfo.get("siteCbUrl") != null && !"".equals(siteVendorInfo.get("siteCbUrl").toString())) {
					callBackObj.put("balance", afBalance);
					if(vendorCetegory.equals("SLOT")) {
						asyncCallBackService.asyncChangeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
					} else {
						asyncCallBackService.asyncChangeBalance(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());
            }
            
            log.error(LOG_PREFIX+ "Error Msg: RESOURCE_ACCESS_ERROR");
            response.setBalance("0");
			response.setId(uuid);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			
			log.error(LOG_PREFIX+ "Error Msg: UNKNOWN_SERVER_ERROR");
			response.setBalance("0");
			response.setId(uuid);
		}
		
		log.info(LOG_PREFIX+ "Response::"+response.toString());
		return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
	}
	
	
	@ResponseBody
	@PostMapping(value = { "/win", "/cancel", "/promo"} )
	public ResponseEntity<SvendorResponse> callResult(HttpServletRequest request, @RequestBody net.sf.json.JSONObject requestBody) throws Exception {
		
		SvendorResponse response = new SvendorResponse();
		String vendorUsername = requestBody.getString("userid");
		String uuid = vendorUsername;
		String vendorGameCode = requestBody.getString("vendor");
		String callbackType = requestBody.getString("type");
		
		//사이트정보
		HashMap sParam = new HashMap<>();
		sParam.put("vendorUsername", vendorUsername);
		sParam.put("vendor", "pink");
		sParam.put("vendorGameCode", vendorGameCode);
		HashMap siteVendorInfo = siteService.getNewSiteVendorInfo(sParam);
		long siteIdx = 0L;
		String memberId = "";
		if(siteVendorInfo != null) {
			siteIdx = Long.parseLong(siteVendorInfo.get("siteIdx").toString());
			memberId = siteVendorInfo.get("memberId").toString();
		} else {
			siteIdx = Long.parseLong(vendorUsername.substring(0, 3), 16);
			memberId = vendorUsername.substring(3, vendorUsername.length());
			
			//사이트정보
			sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId", memberId);
			sParam.put("vendor", "pink");
			sParam.put("vendorGameCode", vendorGameCode);
			siteVendorInfo = siteService.getSiteVendorInfo(sParam);
		}
		
		final String LOG_PREFIX = "#-CB::PINK::"+memberId+"::RESULT::"+requestBody.getString("tr_id")+":::";
		log.info(LOG_PREFIX+ "Request Body::" + requestBody.toString());
		
		if(siteVendorInfo == null) {
			log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
			response.setBalance("0");
			response.setId(uuid);
			response.setStatuscode(1);
			response.setStatus("NOT_FOUND_SITE_INFO");
			log.info(LOG_PREFIX+ "Response::"+response.toString());
			return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
		}
		
		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		// 배팅 고유ID
		String transactionId = requestBody.getString("tr_id");
		log.info(LOG_PREFIX+ "transactionId::"+transactionId);
		// 베팅 참조ID
		String referenceId = requestBody.getString("ref_id");
		log.info(LOG_PREFIX+ "referenceId"+referenceId);
		// 라운드 고유ID
		String roundId = requestBody.getString("round");
		log.info(LOG_PREFIX+ "roundId::"+roundId);
		String tranId = transactionId;
		//String betId = referenceId;
		String betId = roundId+"#"+vendorUsername;
		// 베팅 시각
		String betDateTimeStr = requestBody.getString("processed_at");
		
		// 게임타입
		String gameType = requestBody.getString("game_type").replaceAll(" ", "").toLowerCase();
		// 게임테이블 아이디 (optional)
		String gameId = "";
		if(requestBody.has("game_code")) gameId = requestBody.getString("game_code");
		// 게임코드
		if("promo".equals(callbackType)) {
			gameId = callbackType;
		}
		
		// 게임타이틀
		String gameName = "" ;
		if(requestBody.has("title")) gameName = requestBody.getString("title");
		if("promo".equals(callbackType)) {
			gameName =callbackType;
		}
		// 배팅액
		String amountS = requestBody.getString("amount");
		int amount = 0;
		Double amountD = Double.parseDouble(amountS); 
		amount = amountD.intValue();
		
		try {
			if(siteVendorInfo == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
				response.setBalance("0");
				response.setId(uuid);
				response.setStatuscode(1);
				response.setStatus("NOT_FOUND_SITE_INFO");
				log.info(LOG_PREFIX+ "Response::"+response.toString());
				return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
			}
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			int vendorIdx = Integer.parseInt(siteVendorInfo.get("vendorIdx").toString());
			String vendorCetegory = siteVendorInfo.get("vendorCetegory").toString();
			
			// ##--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.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
				}
				
				// 베팅 체크
				int cntBet = siteService.getBetIdCheck2(betId);
				if(cntBet == 0) {
					log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_BET_INFO");
					response.setBalance("0");
					response.setId(uuid);
					response.setStatuscode(1);
					response.setStatus("NOT_FOUND_BET_INFO");
					log.info(LOG_PREFIX+ "Response::"+response.toString());
					return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
				}
			} else {
				//베팅여부체크
		    	if("cancel".equals(callbackType)) { //베팅없으면 에러
		    		int checkBet = siteService.getSuccDebitCnt(betId);
		    		if(checkBet==0) {
						log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_BET_INFO");
						response.setBalance("0");
						response.setId(uuid);
						response.setStatuscode(1);
						response.setStatus("NOT_FOUND_BET_INFO");
						log.info(LOG_PREFIX+ "Response::"+response.toString());
						return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
		    		}
		    	}
			}
	    	
	    	//초과베팅 체크
	    	int overCreditAmt = 0;
	    	if(vendorCetegory.equals("SLOT") && "win".equals(callbackType)) {
	    		int siteMaxWin = Integer.parseInt(siteVendorInfo.get("siteMaxWin").toString());
	    		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);
				}
	    	}
			
	        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", vendorCetegory);
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pink");
			tranParam.put("vendorTranKey", referenceId);
			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);
			if("cancel".equals(callbackType)) {
				tranParam.put("isCancel", "Y");
			} else {
				tranParam.put("isCancel", "N");
			}
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			JSONObject callBackObj = new JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("betKey", referenceId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "pink");
			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);
			if("cancel".equals(callbackType)) {
				callBackObj.put("isCancel", 1);
			} else {
				callBackObj.put("isCancel", 0);
			}
			if("promo".equals(callbackType)) {
				callBackObj.put("isBonus", 1);
			} else {
				callBackObj.put("isBonus", 0);
			}
			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-----");
				
				JSONObject resData = null;
				if(vendorCetegory.equals("SLOT")) {
					resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
				} else {
					resData = callBackService.changeBalance(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.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
				} else if(resData.getLong("result_code") == 98) {
					// 중복
					int balance = resData.getInt("balance");
					response.setBalance(Integer.toString(balance));
					response.setId(uuid);
					response.setStatuscode(0);
					response.setStatus("OK");
				} else {
					// 실패
					log.error(LOG_PREFIX+ "CALLBACK_ERROR");
					response.setBalance("0");
					response.setId(uuid);
					response.setStatuscode(1);
					response.setStatus("CALLBACK_ERROR");
				}
			} 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.setBalance(Integer.toString(afBalance));
				response.setId(uuid);
				response.setStatuscode(0);
				response.setStatus("OK");
				
				if(siteVendorInfo.get("siteCbUrl") != null && !"".equals(siteVendorInfo.get("siteCbUrl").toString())) {
					callBackObj.put("balance", afBalance);
					if(vendorCetegory.equals("SLOT")) {
						asyncCallBackService.asyncChangeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
					} else {
						asyncCallBackService.asyncChangeBalance(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());
            }
            
            log.error(LOG_PREFIX+ "Error Msg: RESOURCE_ACCESS_ERROR");
            response.setBalance("0");
			response.setId(uuid);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			
			log.error(LOG_PREFIX+ "Error Msg: UNKNOWN_SERVER_ERROR");
			response.setBalance("0");
			response.setId(uuid);
		}
		
		log.info(LOG_PREFIX+ "Response::"+response.toString());
		return new ResponseEntity<SvendorResponse>(response, HttpStatus.OK);
	}
}
