package com.bb.front;

import java.net.SocketTimeoutException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

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.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.model.PandaResponse;
import com.bb.service.AsyncSiteService;
import com.bb.service.CallBackService;
import com.bb.service.SiteService;

import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

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

	@Autowired
	SiteService siteService;
	
	@Autowired
	CallBackService callBackService;
	
	@Autowired
	AsyncSiteService asyncCallBackService;
	
	@ResponseBody
	@RequestMapping(path = "/balance")
	public ResponseEntity<PandaResponse> balance(HttpServletRequest request, @RequestParam("username") String username) throws Exception {
		PandaResponse response = null;
		
		long siteIdx = 0L;
		try {
			siteIdx = Long.parseLong(username.substring(0, 3), 16);
		} catch (NumberFormatException e) {
		    log.error("#-CB::PANDA::balance::Invalid username format (hex expected): {}", username);
		    log.error("#-CB::PANDA::balance::Error Msg: NOT_FOUND_USER");
			response = new PandaResponse();
			response.setBalance(0);
			return new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
		}
		String memberId = username.substring(3, username.length());
		final String LOG_PREFIX = "#-CB::PANDA::balance::"+memberId+":::";
		log.info(LOG_PREFIX+ "Request::" + username);
		
		try {
			//사이트정보
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId", memberId);
			log.info(LOG_PREFIX + "SITE_API_INFO_PARAM::"+sParam.toString());
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			if(siteApiInfo == null) {
				log.error(LOG_PREFIX+ "Error Msg: NOT_FOUND_SITE_INFO");
				response = new PandaResponse();
				response.setBalance(0);
				return new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
			}

			if(siteApiInfo.get("memberIdx") == null) {
				log.error(LOG_PREFIX+ "존재하지 않는 회원");
				response = new PandaResponse();
				response.setBalance(0);
				return new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
			}
			
			// ##--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 = new PandaResponse();
					response.setBalance(0);
					return new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
				}
				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 = new PandaResponse();
			response.setBalance(balance);
			
		} 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 = new PandaResponse();
            response.setBalance(0);
            return new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);

		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			response = new PandaResponse();
			response.setBalance(0);
			return new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		ResponseEntity<PandaResponse> res = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
		log.info(LOG_PREFIX+ "Response::" + response.toString());

		return res;
	}
	
	
	@ResponseBody
	@RequestMapping(path = "/changeBalance")
	public ResponseEntity<PandaResponse> changeBalance(HttpServletRequest request, @RequestBody net.sf.json.JSONObject requestBody) throws Exception {
		ResponseEntity<PandaResponse> resEntity = null;
		
		String username = requestBody.getString("username");
		long siteIdx = 0L;
		try {
			siteIdx = Long.parseLong(username.substring(0, 3), 16);
		} catch (NumberFormatException e) {
		    log.error("#-CB::PANDA::changeBalance::Invalid username format (hex expected): {}", username);
		    log.error("#-CB::PANDA::changeBalance::Error Msg: NOT_FOUND_USER");
		    PandaResponse response = new PandaResponse();
			resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
			return resEntity;
		}
		String memberId = username.substring(3, username.length());
		net.sf.json.JSONObject transaction = requestBody.getJSONObject("transaction");
		net.sf.json.JSONObject game = transaction.getJSONObject("details").getJSONObject("game");
		String transactionId = transaction.getString("id");
		String transactionType = transaction.getString("type");

		final String LOG_PREFIX = "#-CB::PANDA::changeBalance::"+memberId+"::"+transactionId+"::"+transactionType+":::";
		log.info(LOG_PREFIX+ "Request::" + requestBody.toString());
		
		try {
			// "processed_at":"2025-01-16T09:25:23.000000Z"
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
			String betDateTimeStr = transaction.getString("processed_at");
			log.info(LOG_PREFIX+ "========== BF_betDateTimeStr::" + betDateTimeStr);
			betDateTimeStr = betDateTimeStr.substring(0, 19);
			betDateTimeStr = betDateTimeStr.replace("T", " ");
			log.info(LOG_PREFIX+ "========== MF_betDateTimeStr::" + betDateTimeStr);
			betDateTimeStr = makeEdate(LOG_PREFIX, betDateTimeStr, 32400000);
			log.info(LOG_PREFIX+ "========== AF_betDateTimeStr::" + betDateTimeStr);
			
			//사이트정보
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", siteIdx);
			sParam.put("memberId", memberId);
			sParam.put("vendor", "panda");
			sParam.put("vendorGameCode", game.getString("vendor"));
			log.info(LOG_PREFIX + "getSiteVendorInfo::"+sParam.toString());
			HashMap<String,String> siteVendorInfo = siteService.getSiteVendorInfo(sParam);
			if(siteVendorInfo == null) {
				log.error(LOG_PREFIX+ "존재하지 않는 회원입니다");
				PandaResponse response = new PandaResponse();
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
				return resEntity;
			}
			
			if(transactionType.equals("bet")) {
				int amount = Math.abs(requestBody.getInt("amount"));
				resEntity = callBet(LOG_PREFIX, siteIdx, memberId, transaction, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("win")) {
				int amount = Math.abs(requestBody.getInt("amount"));
				resEntity = callWin(LOG_PREFIX, siteIdx, memberId, transaction, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("cancel")) {
				int amount = Math.abs(requestBody.getInt("amount"));
				resEntity = callCancel(LOG_PREFIX, siteIdx, memberId, transaction, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("adjust")) {
				int amount = requestBody.getInt("amount");
				resEntity = callAdjust(LOG_PREFIX, siteIdx, memberId, transaction, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("promo_win")) {
				int amount = Math.abs(requestBody.getInt("amount"));
				resEntity = callPromoWin(LOG_PREFIX, siteIdx, memberId, transaction, betDateTimeStr, siteVendorInfo, amount);
				
			} else if(transactionType.equals("exceed_credit")) {
				log.info(LOG_PREFIX+ "Response::" + resEntity.toString());
				PandaResponse response = new PandaResponse();
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				
			} else if(transactionType.equals("tip")) {
				log.info(LOG_PREFIX+ "Response::" + resEntity.toString());
				PandaResponse response = new PandaResponse();
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				
			} else if(transactionType.equals("charge")) {
				log.info(LOG_PREFIX+ "Response::" + resEntity.toString());
				PandaResponse response = new PandaResponse();
				resEntity = new ResponseEntity<PandaResponse>(response, 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());
            }

            PandaResponse response = new PandaResponse();
			resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
			return resEntity;

		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			PandaResponse response = new PandaResponse();
			resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
			return resEntity;
		}
		
		
		log.info(LOG_PREFIX+ "Response::" + resEntity.toString());
		return resEntity;
	}
	
	
	private ResponseEntity<PandaResponse> callBet(String LOG_PREFIX, long siteIdx, String memberId,
			net.sf.json.JSONObject transaction, String betDateTimeStr, HashMap<String, String> siteVendorInfo,
			int amount) {
		
		LOG_PREFIX = LOG_PREFIX + "callBet:::";
		ResponseEntity<PandaResponse> resEntity = null;
		PandaResponse response = new PandaResponse();

		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		try {
			net.sf.json.JSONObject details = transaction.getJSONObject("details");
			net.sf.json.JSONObject game = details.getJSONObject("game");
			
			String gameType = game.getString("type").replaceAll(" ", "").toLowerCase();
			String gameName = game.getString("title");
			String gameId = game.getString("id");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			String tranId = transaction.getString("id");
			String betId = game.getString("id")+"#"+game.getString("round");
			//String betKey = transaction.getString("referer_id");
			String betKey = betId;
			
			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(balance);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return new ResponseEntity<PandaResponse>(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");
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
					return resEntity;
				}
			}
			
			long siteCredit = Long.parseLong(siteVendorInfo.get("credit").toString());
			// ##--isTransfer 처리-##
			if(siteCredit < amount && IS_TRANSFER.equals("N")) {
				log.error(LOG_PREFIX+ "NO_SITE_CREDIT");
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
				return resEntity;
			}

			// 최대 베팅 금액 처리 (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);
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.BAD_REQUEST);
				return resEntity;
			}
			
			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", "panda");
			tranParam.put("vendorTranKey", betKey);
			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", "P");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			JSONObject callBackObj = new JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("betKey", betKey);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "panda");
			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", "Y");
			callBackObj.put("requestAt", betDateTimeStr);
			
			// ##--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-----");

				log.info(LOG_PREFIX + "SEND_BET request body: " + callBackObj.toString());
				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(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.setBalance(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				} else if(resData.getLong("result_code") == 80) {
					int balance = resData.getInt("balance");
					response.setBalance(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_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(balance);
					log.error(LOG_PREFIX+ "Response::금액을 확인하여 주세요::" + response.toString());
					return new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
				}

				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(afBalance);
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.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());
            }

            resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		return resEntity;
	}


	private ResponseEntity<PandaResponse> callWin(String LOG_PREFIX, long siteIdx, String memberId,
			net.sf.json.JSONObject transaction, String betDateTimeStr, HashMap<String, String> siteVendorInfo,
			int amount) {

		LOG_PREFIX = LOG_PREFIX + "callWin:::";
		ResponseEntity<PandaResponse> resEntity = null;
		PandaResponse response = new PandaResponse();

		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		try {
			net.sf.json.JSONObject details = transaction.getJSONObject("details");
			net.sf.json.JSONObject game = details.getJSONObject("game");
			
			String gameType = game.getString("type").replaceAll(" ", "").toLowerCase();
			String gameName = game.getString("title");
			String gameId = game.getString("id");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			String tranId = transaction.getString("id");
			String betId = game.getString("id")+"#"+game.getString("round");
			//String betKey = transaction.getString("referer_id");
			String betKey = betId;
			
			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(balance);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				}

				// 베팅 체크
				int cntBet = siteService.getBetIdCheck2(betId);
				if(cntBet == 0) {
					// 처리한 베팅 존재X
					log.error(LOG_PREFIX+ "처리한 베팅 존재X");
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
					return resEntity;
				}
			}
			
			//초과베팅 체크
	    	int overCreditAmt = 0;
	    	if(vendorCetegory.equals("SLOT")) {
	    		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", "panda");
			tranParam.put("vendorTranKey", betKey);
			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", "P");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			JSONObject callBackObj = new JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("betKey", betKey);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "panda");
			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", "Y");
			callBackObj.put("requestAt", betDateTimeStr);
			
			// ##--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-----");

				log.info(LOG_PREFIX + "SEND_RESULT request body: " + callBackObj.toString());
				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(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.setBalance(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_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(balance);
					log.error(LOG_PREFIX+ "Response::금액을 확인하여 주세요::" + response.toString());
					return new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
				}

				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(afBalance);
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.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());
            }

            resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		return resEntity;
	}


	private ResponseEntity<PandaResponse> callCancel(String LOG_PREFIX, long siteIdx, String memberId,
			net.sf.json.JSONObject transaction, String betDateTimeStr, HashMap<String, String> siteVendorInfo,
			int amount) {

		LOG_PREFIX = LOG_PREFIX + "callCancel:::";
		ResponseEntity<PandaResponse> resEntity = null;
		PandaResponse response = new PandaResponse();

		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		return resEntity;
	}


	private ResponseEntity<PandaResponse> callAdjust(String LOG_PREFIX, long siteIdx, String memberId,
			net.sf.json.JSONObject transaction, String betDateTimeStr, HashMap<String, String> siteVendorInfo,
			int amount) {

		LOG_PREFIX = LOG_PREFIX + "callAdjust:::";
		ResponseEntity<PandaResponse> resEntity = null;
		PandaResponse response = new PandaResponse();

		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		return resEntity;
	}


	private ResponseEntity<PandaResponse> callPromoWin(String LOG_PREFIX, long siteIdx, String memberId,
			net.sf.json.JSONObject transaction, String betDateTimeStr, HashMap<String, String> siteVendorInfo,
			int amount) {

		LOG_PREFIX = LOG_PREFIX + "callPromoWin:::";
		ResponseEntity<PandaResponse> resEntity = null;
		PandaResponse response = new PandaResponse();

		// ##--isTransfer 처리-##
		final String IS_TRANSFER = siteVendorInfo.get("isTransfer").toString();
		
		try {
			net.sf.json.JSONObject details = transaction.getJSONObject("details");
			net.sf.json.JSONObject game = details.getJSONObject("game");
			
			String gameType = game.getString("type").replaceAll(" ", "").toLowerCase();
			String gameName = game.getString("title");
			String gameId = game.getString("id");
			
			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();
			
			String tranId = transaction.getString("id");
			String betId = game.getString("id")+"#"+game.getString("round");
			//String betKey = transaction.getString("referer_id");
			String betKey = betId;
			
			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(balance);
					log.error(LOG_PREFIX+ "중복요청::Response::" + response.toString());
					return new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				}
			}
			
			//초과베팅 체크
	    	int overCreditAmt = 0;
	    	if(vendorCetegory.equals("SLOT")) {
	    		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", "panda");
			tranParam.put("vendorTranKey", betKey);
			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", "P");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			
			JSONObject callBackObj = new JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("betKey", betKey);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "panda");
			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", "Y");
			callBackObj.put("requestAt", betDateTimeStr);
			
			// ##--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-----");

				log.info(LOG_PREFIX + "SEND_PROMO request body: " + callBackObj.toString());
				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_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.setBalance(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				} else if(resData.getLong("result_code") == 98) {
					int balance = resData.getInt("balance");
					response.setBalance(balance);
					resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.OK);
				} else {
					String msg = "";
					if(resData.has("error_msg")) msg = resData.getString("error_msg");
	 				log.error(LOG_PREFIX+ msg);
	 				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_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(balance);
					log.error(LOG_PREFIX+ "Response::금액을 확인하여 주세요::" + response.toString());
					return new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
				}

				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.setBalance(afBalance);
				resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.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());
            }

            resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "[Exception]"+e.toString());
			e.printStackTrace();
			resEntity = new ResponseEntity<PandaResponse>(response, HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		return resEntity;
	}


	private static String makeEdate(String LOG_PREFIX, String paramDate, int flag) {
		// TODO Auto-generated method stub
		String eDate = "";
		SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		try {
			Date date = sdf1.parse(paramDate);
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(date);
			calendar.add(Calendar.MILLISECOND, flag);
			Date date2 = calendar.getTime();
			eDate = sdf2.format(date2);
		} catch(Exception e) {
			log.error(LOG_PREFIX+ "makeEdate::Exception::"+e.getMessage());
		}
		return eDate;
	}
	
}
