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.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableScheduling;
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 org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientRequestException;
import org.springframework.web.reactive.function.client.WebClientResponseException;

import com.bb.model.GsoftApiInfo;
import com.bb.model.GsoftResponse;
import com.bb.model.GsoftTrxVO;
import com.bb.model.GsoftVO;
import com.bb.service.CallBackService;
import com.bb.service.GsoftService;
import com.bb.service.SiteService;

import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

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

	@Autowired
	SiteService siteService;
	
	@Autowired
	GsoftService gsoftService;
	
	@Autowired
	CallBackService callBackService;
	
	@Autowired
	WebClient webClient;
	
	// https://oprvender.com/api/cb/gsoft/syncBalance
	// https://oprvender.com/api/cb/gsoft/balance
	// https://oprvender.com/api/cb/gsoft/changeBalance
	
	@ResponseBody
	@RequestMapping(path = "/syncBalance")
	public ResponseEntity<GsoftResponse> syncBalance(HttpServletRequest request, @RequestBody GsoftTrxVO gsoftTrxVO) throws Exception {
		GsoftResponse response = null;
		HttpStatus httpStatus = null;
		
		long siteIdx = Long.parseLong(gsoftTrxVO.getUserId().substring(0, 3), 16);
		String memberId = gsoftTrxVO.getUserId().substring(3, gsoftTrxVO.getUserId().length());
		String game = gsoftTrxVO.getGame();
		final String LOG_PREFIX = "#-Gsoft::syncBalance::"+gsoftTrxVO.getUserId()+"::"+game+"::"+gsoftTrxVO.getTranId()+"::::";
		
		log.info(LOG_PREFIX+ "[REQUEST: "+request.getRequestURI()+"] " + gsoftTrxVO);
		
		try {
			log.info(LOG_PREFIX+ "SITE_IDX: "+siteIdx+", USER_INFO: " + memberId+", GAME_INFO: " + game);
			
			HashMap memParam = new HashMap<>();
			memParam.put("siteIdx", siteIdx);
			memParam.put("memberId", memberId);
			memParam.put("vendorGameCode", "SxPRG");
			HashMap userVendorInfo = siteService.getUserVendorInfo(memParam);
			if(userVendorInfo == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO::memParam::" + memParam.toString());
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(gsoftTrxVO.getBalance().intValue());
				httpStatus = HttpStatus.OK;
				return new ResponseEntity<GsoftResponse>(response, httpStatus);
			}
			
			String siteId = userVendorInfo.get("siteId").toString();
//			long memberIdx = (long) siteApiInfo.get("memberIdx");
			long memberIdx = Long.parseLong(userVendorInfo.get("memberIdx").toString());
			
			int amount = Math.abs(gsoftTrxVO.getAmount().intValue());
			int balance = gsoftTrxVO.getBalance().intValue();
			log.info(LOG_PREFIX + "getBalanceUser::SUCC::BF_BALANCE::"+balance);
			
			String tranType = "";
			String type = gsoftTrxVO.getType();
			
			String tranId = siteId + "#" + gsoftTrxVO.getTranId();
			
			HttpHeaders header = new HttpHeaders();				
			header.add("Content-Type", "application/json");
			header.add("Accept", "application/json");
			header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
			
			JSONObject trxObj = new JSONObject();	
			trxObj.put("tranId", tranId);
			trxObj.put("userId", memberId);
			trxObj.put("vendor", "gsoft");
			
			if(type.equals("bet")) {
				tranType = "debit";
				trxObj.put("tranType", tranType);
				balance = balance - amount;
				
			} else {
				// win, lose, cancel
				GsoftApiInfo gsoftApiInfo = GsoftApiInfo.builder()
						.siteIdx(siteIdx)
						.memberIdx(memberIdx)
						.apiBaseUrl(userVendorInfo.get("vendorApiUrl").toString())
						.clientId(userVendorInfo.get("vendorApiId").toString())
						.apiAuthKey(userVendorInfo.get("vendorApiKey").toString())
						.userId(gsoftTrxVO.getUserId())
						.build();
				JSONObject balanceRes = gsoftService.getBalanceUser(gsoftApiInfo);
				if(balanceRes != null && balanceRes.getInt("result") == 1) {
					log.info(LOG_PREFIX + "getBalanceUser::SUCC::AF_BALANCE::"+balance);
					balance = balanceRes.getInt("balance");
					tranType = "balance";
					trxObj.put("tranType", tranType);
				} else {
					log.error(LOG_PREFIX + "Error Msg: BALANCE_ERROR");
					tranType = "credit";
					trxObj.put("tranType", tranType);
					balance = balance + amount;
				}
			}
			
			trxObj.put("amount",  amount);
			trxObj.put("balance", balance);
			
			log.info(LOG_PREFIX + "param: " + trxObj.toString());
			
			String url = userVendorInfo.get("siteCbUrl")+"/changebalance/syncBalance";
			org.springframework.http.ResponseEntity<String> responseEntity = null;
			try {
				responseEntity = webClient.post()
						.uri(url)
						.headers(h -> {
							h.add("Content-Type", "application/json");
							h.add("Accept", "application/json");
							h.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
						})
						.bodyValue(trxObj.toString())
						.retrieve()
						.toEntity(String.class)
						.block();

				log.info(LOG_PREFIX + "/syncBalance status code : {}" + responseEntity.getStatusCode());
				log.info(LOG_PREFIX + "body: " + responseEntity.getBody());
			} catch (WebClientRequestException wcre) {
				Throwable cause = wcre.getCause();
				if(cause instanceof ConnectTimeoutException) {
					log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[ConnectTimeoutException]"+wcre.getMessage());
				}
				if(cause instanceof SocketTimeoutException) {
					log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[SocketTimeoutException]"+wcre.getMessage());
				}
				if(cause instanceof InterruptedException) {
					log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[InterruptedException]"+wcre.getMessage());
				}
				log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[WebClientRequestException]"+wcre.getMessage());
			} catch (WebClientResponseException wre) {
				String str = wre.getResponseBodyAsString();
				log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[WebClientResponseException]"+str);
			}

			JSONObject resData  = new JSONObject(responseEntity != null ? responseEntity.getBody() : "{}");
			log.info(LOG_PREFIX + "result_code: " + resData.getInt("result_code"));
			
			if(resData.getLong("result_code") == 0) {
				log.info(LOG_PREFIX + "CallBack::SUCC");
			} else {
				log.error(LOG_PREFIX + "CallBack::FAIL");
			}	
			
			response = new GsoftResponse();
			response.setResult(1);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
		
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[InterruptedException]"+rae.getMessage());
            }
            
            log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[ResourceAccessException]"+rae.getMessage());
			
			response = new GsoftResponse();
			response.setResult(1);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::[Exception]"+e.getMessage());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
		}
		
		ResponseEntity<GsoftResponse> res = new ResponseEntity<GsoftResponse>(response, httpStatus);
		log.info(LOG_PREFIX+ "### GSOFT API(syncBalance) ###::syncBalance() Response: " + response.toString());
		
		return res;
	}
	
	
	@ResponseBody
	@RequestMapping(path = "/balance")
	public ResponseEntity<GsoftResponse> balance(HttpServletRequest request, @RequestParam("userid") String gsoftUserId) throws Exception {
		GsoftResponse response = null;
		HttpStatus httpStatus = null;
		
		try {
			//사이트정보
			HashMap sParam = new HashMap();
			long siteIdx = Long.parseLong(gsoftUserId.substring(0, 3), 16);
			String memberId = gsoftUserId.substring(3, gsoftUserId.length());
			log.info("#-Gsoft::balance::"+gsoftUserId+"::"+ "SITE_IDX: "+siteIdx+", USER INFO: " + memberId);
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId",  memberId);
			
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			if(siteApiInfo==null) {
				log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "Error Msg: NOT_FOUND_SITE_INFO");
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				httpStatus = HttpStatus.OK;
				return new ResponseEntity<GsoftResponse>(response, httpStatus);
			}
			
			JSONObject member = new JSONObject();
			member.put("userId", memberId);
			log.info("#-Gsoft::balance::"+gsoftUserId+"::"+ "Callback URL::" + siteApiInfo.get("siteCbUrl")+"/balance");
			log.info("#-Gsoft::balance::"+gsoftUserId+"::"+ "Callback Param::" + member.toString());
			
			HttpHeaders header = new HttpHeaders();				
			header.add("Content-Type", "application/json");
			header.add("Accept", "application/json");
			header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
			String url = siteApiInfo.get("siteCbUrl")+"/balance";
			org.springframework.http.ResponseEntity<String> responseEntity = null;
			try {
				responseEntity = webClient.post()
						.uri(url)
						.headers(h -> {
							h.add("Content-Type", "application/json");
							h.add("Accept", "application/json");
							h.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
						})
						.bodyValue(member.toString())
						.retrieve()
						.toEntity(String.class)
						.block();

				log.info("#-Gsoft::balance::"+gsoftUserId+"::"+ "Callback Status code::" + responseEntity.getStatusCode());
				log.info("#-Gsoft::balance::"+gsoftUserId+"::"+ "Callback Response body::" + responseEntity.getBody());
			} catch (WebClientRequestException wcre) {
				Throwable cause = wcre.getCause();
				if(cause instanceof ConnectTimeoutException) {
					log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[ConnectTimeoutException]"+wcre.getMessage());
				}
				if(cause instanceof SocketTimeoutException) {
					log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[SocketTimeoutException]"+wcre.getMessage());
				}
				if(cause instanceof InterruptedException) {
					log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[InterruptedException]"+wcre.getMessage());
				}
				log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[WebClientRequestException]"+wcre.getMessage());
			} catch (WebClientResponseException wre) {
				String str = wre.getResponseBodyAsString();
				log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[WebClientResponseException]"+str);
			}

			JSONObject resData  = new JSONObject(responseEntity != null ? responseEntity.getBody() : "{}");
			int balance = resData.getInt("balance");
			
			response = new GsoftResponse();
			response.setResult(1);
			response.setBalance(balance);
			httpStatus = HttpStatus.OK;
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[InterruptedException]"+rae.getMessage());
            }
            
            log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[ResourceAccessException]"+rae.getMessage());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
			
		} catch (Exception e) {
			log.error("#-Gsoft::balance::"+gsoftUserId+"::"+ "[Exception]"+e.getMessage());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
		}
		
		ResponseEntity<GsoftResponse> res = new ResponseEntity<GsoftResponse>(response, httpStatus);
		log.info("#-Gsoft::balance::"+gsoftUserId+"::"+ "Response: "+response.toString());
		
		return res;
	}
	
	@ResponseBody
	@RequestMapping(path = "/changeBalance")
	public ResponseEntity<GsoftResponse> changeBalance(HttpServletRequest request, @RequestBody GsoftVO gsoftVO) throws Exception {
		GsoftResponse response = null;
		HttpStatus httpStatus = null;
		
		String gsofIdx = gsoftVO.getRealRound();
		String gsofTranType = gsoftVO.getType().toUpperCase();
		String gsofGame = gsoftVO.getGame();
		String gsoftUserId = gsoftVO.getUserId();
		
		final String LOG_PREFIX = "#-Gsoft::changeBalance::"+gsoftUserId+"::"+gsofGame+"::"+gsofIdx+"::"+gsofTranType+"::::";
		
		try {
			log.info(LOG_PREFIX+ "GsoftVO::"+gsoftVO.toString());
			
			//사이트정보
			long siteIdx = Long.parseLong(gsoftUserId.substring(0, 3), 16);
			String memberId = gsoftUserId.substring(3, gsoftUserId.length());
			log.info(LOG_PREFIX+ "SITE_IDX: "+siteIdx+", USER INFO: " + memberId);
			/*
			HashMap memParam = new HashMap<>();
			memParam.put("siteIdx", siteIdx);
			memParam.put("memberId", memberId);
			memParam.put("vendorGameCode", gsofGame);
			HashMap userVendorInfo = siteService.getUserVendorInfo(memParam);
			log.info(LOG_PREFIX+ "userVendorInfo::"+userVendorInfo.toString());
			*/
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId", memberId);
			sParam.put("vendor", "gsoft");
			sParam.put("vendorGameCode", gsofGame);
			log.info(LOG_PREFIX + "getSiteVendorInfo::"+sParam.toString());
			HashMap<String,String> siteVendorInfo = siteService.getSiteVendorInfo(sParam);
			if(siteVendorInfo == null || siteVendorInfo.get("vendorApiId") == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				httpStatus = HttpStatus.OK;
				return new ResponseEntity<GsoftResponse>(response, httpStatus);
			}
			String siteId = siteVendorInfo.get("siteId").toString();
			
			if(gsoftVO.getType().equals("bet")) {
				// bet 요청
				response = callDebit(gsoftVO, siteVendorInfo, siteId, memberId, LOG_PREFIX);
				
			} else if(gsoftVO.getType().equals("win") || gsoftVO.getType().equals("lose") || gsoftVO.getType().equals("cancel")) {
				// win, lose, cancel 요청
				if(gsoftVO.getType().equals("lose")) {
					// 미당첨 시 금액 == 0
					gsoftVO.setAmount(0);
				}
				response = callCredit(gsoftVO, siteVendorInfo, siteId, memberId, LOG_PREFIX);
				
			} else {
			}
			
			if(response != null && response.getResult() == 1) {
				httpStatus = HttpStatus.OK;
			} else {
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				httpStatus = HttpStatus.OK;
			}
			
		} 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());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.getMessage());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			httpStatus = HttpStatus.OK;
		}
		
		ResponseEntity<GsoftResponse> res = new ResponseEntity<GsoftResponse>(response, httpStatus);
		log.info(LOG_PREFIX+ "Response: "+response.toString() + ", HttpStatus: " + httpStatus);
		
		return res;
	}


	private GsoftResponse callDebit(GsoftVO gsoftVO, HashMap<String,String> siteVendorInfo, String siteId, String memberId, final String LOG_PREFIX) {
		GsoftResponse response = null;
		
		log.info(LOG_PREFIX+ "callDebit::START");
		try {
			String vendorTranKey = gsoftVO.getTranId();
			String tranId = siteId + "#" + vendorTranKey;
			String betId = siteId + "#" + gsoftVO.getRealRound();
			
			// 중복체크
			long chs1 = System.currentTimeMillis();
			int betCnt = siteService.getBotaBetCnt(tranId);
			long che1 = System.currentTimeMillis(); // 코드 실행 후에 시간 받아오기
			double diff1 = (chs1 - che1)/1000.0; //두 시간에 차 계산
			log.error(LOG_PREFIX+ "Duplicate check::" + String.format("%.3f", diff1));
			if(betCnt != 0) {
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				log.error(LOG_PREFIX + "Duplicate tranId: " + tranId);
				return response;
			}
			
			int amount = Math.abs(gsoftVO.getAmount());
			long amountL = amount;
			long targetSiteCredit = Long.parseLong(siteVendorInfo.get("credit").toString());
			if(targetSiteCredit < amountL) {
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				log.error(LOG_PREFIX + "no_site_credit");
				return response;
			}
			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 = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				log.error(LOG_PREFIX + "MAX_BET_AMOUNT_OVER");
				return response;
			}
			
			long siteIdx = Long.parseLong(siteVendorInfo.get("siteIdx").toString());
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			String siteCbUrl = siteVendorInfo.get("siteCbUrl").toString();
//			HashMap vendorInfo = siteService.getGsoftVendorInfo(gsoftVO.getGame());
			long vendorIdx = Integer.parseInt(siteVendorInfo.get("vendorIdx").toString());
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			String vendorCetegory = siteVendorInfo.get("vendorCetegory").toString();
			
			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", "gsoft");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameIdx", gsoftVO.getTitle());
			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);
			
			long startTime = System.currentTimeMillis();
			siteService.commonBetinsert(tranParam);
			long endTime = System.currentTimeMillis(); // 코드 실행 후에 시간 받아오기
			double diffTime = (startTime - endTime)/1000.0; //두 시간에 차 계산
			if(diffTime < -1.0) {
				log.error(LOG_PREFIX + "배팅 쓰기지연:"+diffTime+"초 지연발생");
	            response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				return response;
			}
			log.info(LOG_PREFIX + "siteService.commonBetinsert() END");
			/*
			HttpHeaders header = new HttpHeaders();
			header.add("Content-Type", "application/json");
			header.add("Accept", "application/json");
			header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
			*/
			JSONObject debit = new JSONObject();
			debit.put("betId", betId);
			debit.put("tranId", tranId);
			debit.put("userId", memberId);
			debit.put("vendorIdx", vendorIdx);
			debit.put("vendorKey", vendorKey);
			debit.put("vendor", "gsoft");
			debit.put("gameIdx", vendorIdx);
			debit.put("gameKey", gsoftVO.getTitle());
			debit.put("tranType", "debit");
			debit.put("debit", amount);
			debit.put("credit", 0);
			debit.put("isCancel", 0);
			debit.put("isBonus", 0);
			debit.put("requestAt", gsoftVO.getTime());

			JSONObject resData = new JSONObject();
			if(vendorCetegory.equals("SLOT")) {
				log.info(LOG_PREFIX + "SEND_DEBIT::changeBalanceSlot::param: " + debit.toString());
				resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, debit);
				log.info(LOG_PREFIX + "SEND_DEBIT::changeBalanceSlot::status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_DEBIT::changeBalanceSlot::response body: " + resData.toString());
			} else {
				log.info(LOG_PREFIX + "SEND_DEBIT::changeBalance::param: " + debit.toString());
				resData = callBackService.changeBalance(LOG_PREFIX, siteVendorInfo, debit);
				log.info(LOG_PREFIX + "SEND_DEBIT::changeBalance::status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_DEBIT::changeBalance::response body: " + resData.toString());
			}
			
			if(resData.getLong("result_code") == 0) {
				tranParam.put("balance", resData.getInt("balance"));
				int res = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "siteService.updateCbApi() END");
				int balance = resData.getInt("balance");
				
				response = new GsoftResponse();
				response.setResult(1);
				response.setBalance(balance);
			} else {
				String msg = "";
				if(resData.has("error_msg")) msg = resData.getString("error_msg");
				log.error(LOG_PREFIX + "result_code:"+resData.getLong("result_code"));
				log.error(LOG_PREFIX + "error_msg:"+msg);
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
			}
			
		} 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());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+ e.toString());
		}
		log.info(LOG_PREFIX+ "callDebit::END");
		
		return response;
	}


	private GsoftResponse callCredit(GsoftVO gsoftVO, HashMap<String,String> siteVendorInfo, String siteId, String memberId, final String LOG_PREFIX) {
		GsoftResponse response = null;
		
		log.info(LOG_PREFIX+ "callCredit::START");
		try {
			String vendorTranKey = gsoftVO.getTranId();
			String tranId = siteId + "#" + vendorTranKey;
			String betId = siteId + "#" + gsoftVO.getRealRound();
			
			// Debit 체크
			long chs1 = System.currentTimeMillis();
			int debitCnt = siteService.getSuccDebitCnt(betId);
			long che1 = System.currentTimeMillis(); // 코드 실행 후에 시간 받아오기
			double diff1 = (chs1 - che1)/1000.0; //두 시간에 차 계산
			log.error(LOG_PREFIX+ "Debit check::" + String.format("%.3f", diff1));
			if(debitCnt == 0) {
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				log.error(LOG_PREFIX + "Not found success debit by betId: " + betId);
				return response;
			}
			
			// 중복체크
			long chs2 = System.currentTimeMillis();
			int betCnt = siteService.getBotaBetCnt(tranId);
			long che2 = System.currentTimeMillis(); // 코드 실행 후에 시간 받아오기
			double diff2 = (chs2 - che2)/1000.0; //두 시간에 차 계산
			log.error(LOG_PREFIX+ "Duplicate check::" + String.format("%.3f", diff2));
			if(betCnt != 0) {
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				log.error(LOG_PREFIX + "Duplicate tranId: " + tranId);
				return response;
			}
			
			int amount = Math.abs(gsoftVO.getAmount());
			
			long siteIdx = Long.parseLong(siteVendorInfo.get("siteIdx").toString());
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			String siteCbUrl = siteVendorInfo.get("siteCbUrl").toString();
//			HashMap vendorInfo = siteService.getGsoftVendorInfo(gsoftVO.getGame());
			long vendorIdx = Integer.parseInt(siteVendorInfo.get("vendorIdx").toString());
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			String vendorCetegory = siteVendorInfo.get("vendorCetegory").toString();
			
			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", "gsoft");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameIdx", gsoftVO.getTitle());
			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", 0);
			tranParam.put("creditAmt", amount);
			if(gsoftVO.getType().equals("cancel")) {
				tranParam.put("isCancel", "Y");
			} else {
				// win, lose
				tranParam.put("isCancel", "N");
			}
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			long startTime = System.currentTimeMillis();
			siteService.commonBetinsert(tranParam);
			long endTime = System.currentTimeMillis(); // 코드 실행 후에 시간 받아오기
			double diffTime = (startTime - endTime)/1000.0; //두 시간에 차 계산
			if(diffTime < -1.0) {
				log.error(LOG_PREFIX + "배팅 쓰기지연:"+diffTime+"초 지연발생");
	            response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
				return response;
			}
			log.info(LOG_PREFIX + "siteService.commonBetinsert() END");
			/*
			HttpHeaders header = new HttpHeaders();
			header.add("Content-Type", "application/json");
			header.add("Accept", "application/json");
			header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" + " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
			*/
			JSONObject credit = new JSONObject();
			credit.put("betId", betId);
			credit.put("tranId", tranId);
			credit.put("userId", memberId);
			credit.put("vendorIdx", vendorIdx);
			credit.put("vendorKey", vendorKey);
			credit.put("vendor", "gsoft");
			credit.put("gameIdx", vendorIdx);
			credit.put("gameKey", gsoftVO.getTitle());
			credit.put("tranType", "credit");
			credit.put("debit", 0);
			credit.put("credit", amount);
			if(gsoftVO.getType().equals("cancel")) {
				credit.put("isCancel", 1);
			} else {
				// win, lose
				credit.put("isCancel", 0);
			}
			credit.put("isBonus", 0);
			credit.put("requestAt", gsoftVO.getTime());

			JSONObject resData = new JSONObject();
			if(vendorCetegory.equals("SLOT")) {
				log.info(LOG_PREFIX + "SEND_CREDIT::changeBalanceSlot::param: " + credit.toString());
				resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, credit);
				log.info(LOG_PREFIX + "SEND_CREDIT::changeBalanceSlot::status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_CREDIT::changeBalanceSlot::response body: " + resData.toString());
			} else {
				log.info(LOG_PREFIX + "SEND_CREDIT::changeBalance::param: " + credit.toString());
				resData = callBackService.changeBalance(LOG_PREFIX, siteVendorInfo, credit);
				log.info(LOG_PREFIX + "SEND_CREDIT::changeBalance::status code: " + resData.getLong("result_code"));
				log.info(LOG_PREFIX + "SEND_CREDIT::changeBalance::response body: " + resData.toString());
			}
			if(resData.getLong("result_code") == 0) {
				tranParam.put("balance", resData.getInt("balance"));
				int res = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "siteService.updateCbApi() END");
				
				int balance = resData.getInt("balance");
				
				response = new GsoftResponse();
				response.setResult(1);
				response.setBalance(balance);
			} else {
				String msg = "";
				if(resData.has("error_msg")) msg = resData.getString("error_msg");
				log.error(LOG_PREFIX + "error_msg:"+msg);
				response = new GsoftResponse();
				response.setResult(0);
				response.setBalance(0);
			}
			
		} 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());
			
			response = new GsoftResponse();
			response.setResult(0);
			response.setBalance(0);
			
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+ e.toString());
		}
		log.info(LOG_PREFIX+ "callCredit::END");
		
		return response;
	}
}
