package com.bb.front;

import java.net.URLDecoder;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.codehaus.jettison.json.JSONException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
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.reactive.function.client.WebClient;

import com.bb.jwt.JwtManager;
import com.bb.model.BetParam;
import com.bb.model.Member;
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;
import net.sf.json.JSONObject;

@RestController
@Slf4j
@RequestMapping("/api/callback/pp/")
@RequiredArgsConstructor
@SecurityRequirement(name = "Authorization")
public class CallBackPragmaticController {

	@Autowired
	private final JwtManager jwtManager;
	
	@Autowired
	SiteService siteService;

	@Autowired
	WebClient webClient;

	@Autowired
	CallBackService callBackService;
	
	@Autowired
	AsyncSiteService asyncCallBackService;

	@CrossOrigin
	@PostMapping(value = "/Authenticate")
	public @ResponseBody JSONObject authenticate(HttpServletRequest request,
			@RequestBody(required = false) String parambody) throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("token"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		/*
		 * String ipAdress = URLDecoder.decode(request.getParameter("ipAdress"),
		 * "UTF-8"); String chosenBalance =
		 * URLDecoder.decode(request.getParameter("chosenBalance"), "UTF-8"); String
		 * lunchingType = URLDecoder.decode(request.getParameter("lunchingType"),
		 * "UTF-8"); String proviousToken =
		 * URLDecoder.decode(request.getParameter("proviousToken"), "UTF-8");
		 */

		try {
			//String userId = token;
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::authenticate:::";
			log.info(LOG_PREFIX+ "userId : " + userId);
			
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			log.info(LOG_PREFIX+ "siteApiInfo {}", siteApiInfo);
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();
			
			
			double balance = 0L;
			// ##--isTransfer 처리-##
			if (IS_TRANSFER.equals("Y")) {
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
				balanceMap.put("memberId", memberId);
				balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
				
				if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
					org.codehaus.jettison.json.JSONObject member = new org.codehaus.jettison.json.JSONObject();
					member.put("userId", memberId);
					member.put("balance", balance);
					asyncCallBackService.asyncBalance(LOG_PREFIX, siteApiInfo, member);
				}

			} else {
				DecimalFormat formatter = new DecimalFormat("0.##");

				org.codehaus.jettison.json.JSONObject memberParam = new org.codehaus.jettison.json.JSONObject();
				memberParam.put("userId", memberId);
				org.codehaus.jettison.json.JSONObject cbResData = callBackService.getBalance(siteApiInfo, memberParam);
				balance = cbResData.getDouble("balance");
			}

			double bonus = 0.00;
			resData.put("userId", siteApiInfo.get("siteIdxHex").toString() + memberId);
			resData.put("currency", "VND");
			resData.put("cash", balance);
			resData.put("bonus", bonus);
			resData.put("error", 0);
			resData.put("description", "Success");

		} catch (Exception e) {
			log.info(e.toString());
			resData.put("error", 2);
			resData.put("description", "Player not found or logged out.");
		    
		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/Balance")
	public @ResponseBody JSONObject balance(HttpServletRequest request, @RequestBody(required = false) String parambody)
			throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		// String token = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		/*
		 * String ipAdress = URLDecoder.decode(request.getParameter("ipAdress"),
		 * "UTF-8"); String chosenBalance =
		 * URLDecoder.decode(request.getParameter("chosenBalance"), "UTF-8"); String
		 * lunchingType = URLDecoder.decode(request.getParameter("lunchingType"),
		 * "UTF-8"); String proviousToken =
		 * URLDecoder.decode(request.getParameter("proviousToken"), "UTF-8");
		 */

		try {
			HashMap sParam = new HashMap();
			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::balance:::";

			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();
			double balance = 0L;
			// ##--isTransfer 처리-##
			if (IS_TRANSFER.equals("Y")) {
				HashMap balanceMap = new HashMap<>();
				balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
				balanceMap.put("memberId", memberId);
				balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
				
				if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
					org.codehaus.jettison.json.JSONObject member = new org.codehaus.jettison.json.JSONObject();
					member.put("userId", memberId);
					member.put("balance", balance);
					asyncCallBackService.asyncBalance(LOG_PREFIX, siteApiInfo, member);
				}

			} else {

				org.codehaus.jettison.json.JSONObject memberParam = new org.codehaus.jettison.json.JSONObject();
				memberParam.put("userId", memberId);
				org.codehaus.jettison.json.JSONObject cbResData = callBackService.getBalance(siteApiInfo, memberParam);
				balance = cbResData.getDouble("balance");
			}

			double bonus = 0.00;

			resData.put("currency", "VND");
			resData.put("cash", balance);
			resData.put("bonus", bonus);
			resData.put("error", 0);
			resData.put("description", "Success");

		} catch (Exception e) {			
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");
		    

		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/Bet")
	public @ResponseBody JSONObject bet(HttpServletRequest request, @RequestBody(required = false) String parambody)
			throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String gameId = URLDecoder.decode(request.getParameter("gameId"), "UTF-8");
		String roundId = URLDecoder.decode(request.getParameter("roundId"), "UTF-8");
		String amountStr = URLDecoder.decode(request.getParameter("amount"), "UTF-8");
		String reference = URLDecoder.decode(request.getParameter("reference"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		String timestamp = URLDecoder.decode(request.getParameter("timestamp"), "UTF-8");
		String roundDetails = URLDecoder.decode(request.getParameter("roundDetails"), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::bet:::";
			log.info(LOG_PREFIX+ "# sparam () : " + sParam.toString());

			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam siteApiInfo () : " + siteApiInfo.toString());

			if (siteApiInfo == null) {
				log.info(LOG_PREFIX+ "# sparam BET 0() : no setting");
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// ##--isTransfer 처리-##
			log.info(LOG_PREFIX+ "# sparam authParam {} ", authParam.toString());
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				log.info(LOG_PREFIX+ "# sparam BET1 () : no member");
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			long targetSiteCredit = siteService.getSiteCredit(siteApiInfo.get("siteId").toString());
			log.info(LOG_PREFIX+ "# sparam targetSiteCredit {} ", targetSiteCredit);

			double amount = Double.parseDouble(amountStr);
			log.info(LOG_PREFIX+ "# sparam amount {} ", amount);
			

			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();

			if ((targetSiteCredit < amount || targetSiteCredit < 0) && IS_TRANSFER.equals("N") ) {
				log.info(LOG_PREFIX+ "# sparam BET2 () : no cash");
				resData.put("error", 1);			
				resData.put("description", "Insufficient balance");
				return resData;
			}

			int vendorIdx = 17;
			String vendorKey = "S02";
			String vendorCetegory = "SLOT";
			if (!(gameId.startsWith("vs") || gameId.startsWith("cs"))) {
				vendorIdx = 2;
				vendorKey = "C02";
				vendorCetegory = "CASINO";
			}

			sParam.put("vendorIdx", vendorIdx);
			long maxBet = siteService.getSiteMaxBet(sParam);
			
			// userMaxBet 조회 (userMaxBet 우선 적용)
			long userMaxBet = 0;
			Long userMaxBetObj = siteService.getUserMaxBet(sParam);
			if(userMaxBetObj != null) {
				userMaxBet = userMaxBetObj;
			}
			
			// 최종 maxBet 결정: userMaxBet이 0이면 siteMaxBet 사용, 0이 아니면 userMaxBet 사용
			long finalMaxBet = (userMaxBet > 0) ? userMaxBet : maxBet;
			log.info(LOG_PREFIX+ "MaxBet Info - siteMaxBet: " + maxBet + ", userMaxBet: " + userMaxBet + ", finalMaxBet: " + finalMaxBet);

			if (amount > finalMaxBet) {
				log.info(LOG_PREFIX + "# sparam finalMaxBet {} ", finalMaxBet);
				log.info(LOG_PREFIX + "# sparam BET3 () : max bet limit");
				resData.put("error", 310);
				resData.put("description", "bet limits");

				return resData;
			}

			HashMap tranParam = new HashMap();

			String refId = siteId + roundId;

			log.info(LOG_PREFIX+ "# sparam refId {}", siteId + roundId);

			tranParam.put("tranId", siteId + reference);
			tranParam.put("refId", refId);
			tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			tranParam.put("siteId", siteId);
			tranParam.put("completed", true);
			tranParam.put("memberIdx", member.getMemberIdx());
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", vendorCetegory);
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pragmatic");
			tranParam.put("vendorTranKey", reference);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", gameId);
			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", "dfngtnslt_est88");

			tranParam.put("isTransfer", IS_TRANSFER);
			double balance = 0L;			
			
			org.codehaus.jettison.json.JSONObject debit = new org.codehaus.jettison.json.JSONObject();
			double fakeAmount = amount;// *100;
			debit.put("betId", refId);
			debit.put("tranId", siteId + reference);

			debit.put("userId", member.getMemberId());
			debit.put("vendorIdx", vendorIdx);
			debit.put("vendorKey", vendorKey);
			debit.put("vendor", "pragmatic");
			debit.put("gameIdx", 1);
			debit.put("gameKey", gameId);
			debit.put("gameType", "slot");
			debit.put("gameId", gameId);
			debit.put("tranType", "debit");
			debit.put("debit", fakeAmount);
			debit.put("credit", 0);
			debit.put("isCancel", 0);
			debit.put("isBonus", 0);
			debit.put("decYn", "Y");	

			if (IS_TRANSFER.equals("Y")) {

			
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(siteId + reference);
				

				try {
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));

					if (balance < amount) {
						resData.put("error", 1);
						resData.put("description","Insufficient balance");						
						return resData;
					}
					
					
					if (cntTr == 0) {						
						siteService.commonBetinsert(tranParam);					
					}
					double afBalance = balance - amount;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", (double)afBalance);
					tranParam.put("preBalance", (double)balance);
					if (cntTr == 0) {						
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					if (cntTr == 0) {	
						resData.put("cash", afBalance);
					}else {
						resData.put("cash", balance);
					}
					resData.put("bonus", 0);
					resData.put("usedPromo", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
					
					if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
						debit.put("balance", afBalance);
						if(vendorCetegory.equals("SLOT")) {
							asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC BET - ", siteApiInfo, debit);
						} else {
							asyncCallBackService.asyncChangeBalance("PRAGMATIC BET - ", siteApiInfo, debit);
						}
					}

				} catch (Exception e) {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
					
					
					
					
					return resData;
				}

			} else {

				siteService.commonBetinsert(tranParam);
			
				org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();

				if (vendorCetegory.equals("SLOT")) {
					cbResData = callBackService.changeBalanceSlot("PRAGMATIC BET - ", siteApiInfo, debit);
				} else {
					cbResData = callBackService.changeBalance("PRAGMATIC BET - ", siteApiInfo, debit);
				}

				log.info(LOG_PREFIX+ "cbResData {}", cbResData.toString());

				if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
					if (cbResData.getLong("result_code") == 0 ) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
					resData.put("bonus", 0);
					resData.put("usedPromo", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
				} else if (cbResData.getLong("result_code") == 80) {
					resData.put("error", 1);			
					resData.put("description", "Insufficient balance");
					return resData;
				} else if (cbResData.getLong("result_code") == 81) {
					resData.put("error", 310);			
					resData.put("description",  "bet limits");
					return resData;
				} else {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::bet:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");

		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/Refund")
	public @ResponseBody JSONObject refund(HttpServletRequest request, @RequestBody(required = false) String parambody)
			throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String reference = URLDecoder.decode(request.getParameter("reference"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::refund:::";
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {

				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// 회원정보
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			// 베팅 정보 가져오기 없으면 에러
			HashMap betInfo = siteService.getBetInfoByTranId(reference);

			double amount = Double.parseDouble(betInfo.get("depositAmt").toString());
			
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();
			
			
			int vendorIdx = Integer.parseInt(betInfo.get("vendorIdx").toString());			
			String vendorKey = "S02";
			String vendorCetegory = "SLOT";
			if(vendorIdx!=17) {
				vendorKey = "C02";
				vendorCetegory = "CASINO";
			}
		
			HashMap tranParam = new HashMap();

			String refId = betInfo.get("refId").toString();

			tranParam.put("tranId", betInfo.get("tranId").toString() + "#R");
			tranParam.put("refId", refId);
			tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			tranParam.put("siteId", siteId);
			tranParam.put("completed", true);
			tranParam.put("memberIdx", member.getMemberIdx());
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", vendorCetegory);
			tranParam.put("vendorIdx", Integer.parseInt(betInfo.get("vendorIdx").toString()));
			tranParam.put("vendorCode", "pragmatic");
			tranParam.put("vendorTranKey", reference);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", betInfo.get("gameIdx").toString());
			tranParam.put("gameIdx", betInfo.get("gameIdx").toString());

			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("isCancel", "Y");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", "dfngtnslt_est88");
			
			tranParam.put("isTransfer", IS_TRANSFER);	
			

			org.codehaus.jettison.json.JSONObject debit = new org.codehaus.jettison.json.JSONObject();
			double fakeAmount = amount;// *100;
			debit.put("betId", refId);
			debit.put("tranId", betInfo.get("tranId").toString() + "#R");

			debit.put("userId", member.getMemberId());
			debit.put("vendorIdx", vendorIdx);
			debit.put("vendorKey", vendorKey);
			debit.put("vendor", "pragmatic");
			debit.put("gameIdx", 1);
			debit.put("gameKey", betInfo.get("gameIdx").toString());
			debit.put("gameType", "slot");
			debit.put("gameId", betInfo.get("gameIdx").toString());
			debit.put("tranType", "credit");
			debit.put("debit", 0);
			debit.put("credit", fakeAmount);
			debit.put("isCancel", 1);
			debit.put("isBonus", 0);
			debit.put("decYn", "Y");
			
						
			if (IS_TRANSFER.equals("N")) {
				siteService.commonBetinsert(tranParam);
				org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();		
				if (vendorCetegory.equals("SLOT")) {
					cbResData = callBackService.changeBalanceSlot("PRAGMATIC REFUND - ", siteApiInfo, debit);
				} else {
					cbResData = callBackService.changeBalance("PRAGMATIC REFUND - ", siteApiInfo, debit);
				}		
	
				if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
					
					if (cbResData.getLong("result_code") == 0 ) {
						int res = siteService.updateCbApi(tranParam);
					}
	
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
	
				} else {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			
			}else {				
				
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(betInfo.get("tranId").toString() + "#R");
				
				if(cntTr==0) {
				siteService.commonBetinsert(tranParam);
				}
				try {
					double balance = 0L;	
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
					
					double afBalance = balance + amount;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", (double)afBalance);
					tranParam.put("preBalance", (double)balance);
					if(cntTr==0) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					if(cntTr==0) {
						resData.put("cash", afBalance);
					}else {
						resData.put("cash", balance);
					}
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
					
					if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
						debit.put("balance", afBalance);
						if(vendorCetegory.equals("SLOT")) {
							asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC REFUND - ", siteApiInfo, debit);
						} else {
							asyncCallBackService.asyncChangeBalance("PRAGMATIC REFUND - ", siteApiInfo, debit);
						}
					}

				}catch(Exception e) {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::refund:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");
		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/Result")
	public @ResponseBody JSONObject result(HttpServletRequest request, @RequestBody(required = false) String parambody)
			throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String gameId = URLDecoder.decode(request.getParameter("gameId"), "UTF-8");
		String roundId = URLDecoder.decode(request.getParameter("roundId"), "UTF-8");
		String amountStr = URLDecoder.decode(request.getParameter("amount"), "UTF-8");
		String reference = URLDecoder.decode(request.getParameter("reference"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		String timestamp = URLDecoder.decode(request.getParameter("timestamp"), "UTF-8");
		String roundDetails = URLDecoder.decode(request.getParameter("roundDetails"), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::result:::";
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {

				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// 회원정보
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			double amount = Double.parseDouble(amountStr);
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();

			int vendorIdx = 17;
			String vendorKey = "S02";
			String vendorCetegory = "SLOT";
			if (!(gameId.startsWith("vs") || gameId.startsWith("cs"))) {
				vendorIdx = 2;
				vendorKey = "C02";
				vendorCetegory = "CASINO";
			}

			HashMap tranParam = new HashMap();

			String refId = siteId + roundId;

			tranParam.put("tranId", siteId + reference);
			tranParam.put("refId", refId);
			tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			tranParam.put("siteId", siteId);
			tranParam.put("completed", true);
			tranParam.put("memberIdx", member.getMemberIdx());
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", vendorCetegory);
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pragmatic");
			tranParam.put("vendorTranKey", reference);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", gameId);

			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", "dfngtnslt_est88");
			tranParam.put("isTransfer", IS_TRANSFER);	

		

			org.codehaus.jettison.json.JSONObject  debit = new org.codehaus.jettison.json.JSONObject ();
			double fakeAmount = amount;// *100;
			debit.put("betId", refId);
			debit.put("tranId", siteId + reference);

			debit.put("userId", member.getMemberId());
			debit.put("vendorIdx", vendorIdx);
			debit.put("vendorKey", vendorKey);
			debit.put("vendor", "pragmatic");
			debit.put("gameIdx", 1);
			debit.put("gameKey", gameId);
			debit.put("gameType", "slot");
			debit.put("gameId", gameId);
			debit.put("tranType", "credit");
			debit.put("debit", 0);
			debit.put("credit", fakeAmount);
			debit.put("isCancel", 0);
			debit.put("isBonus", 0);
			debit.put("decYn", "Y");
			
			

			if (IS_TRANSFER.equals("N")) {
				
				siteService.commonBetinsert(tranParam);
				
				org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();		
				if (vendorCetegory.equals("SLOT")) {
					cbResData = callBackService.changeBalanceSlot("PRAGMATIC SEAMLESS Result - ", siteApiInfo, debit);
				} else {
					cbResData = callBackService.changeBalance("PRAGMATIC SEAMLESS Result - ", siteApiInfo, debit);
				}		
				
				if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
					if (cbResData.getLong("result_code") == 0) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
	
				} else {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
				
			}else {
				
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(siteId + reference);
				
						
				if(cntTr == 0) {
					siteService.commonBetinsert(tranParam);
				}
				
				try {
					double balance = 0L;	
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
					
					double afBalance = balance + amount;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", (double)afBalance);
					tranParam.put("preBalance", (double)balance);
					if(cntTr == 0) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					if(cntTr == 0) {
						resData.put("cash", afBalance);
					}else {
						resData.put("cash", balance);
					}
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
					
					if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
						debit.put("balance", afBalance);
						if(vendorCetegory.equals("SLOT")) {
							asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC TRANSFER RESULT - ", siteApiInfo, debit);
						} else {
							asyncCallBackService.asyncChangeBalance("PRAGMATIC TRANSFER RESULT - ", siteApiInfo, debit);
						}
					}

				}catch(Exception e) {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::result:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");

		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/BonusWin")
	public @ResponseBody JSONObject bonusWin(HttpServletRequest request,
			@RequestBody(required = false) String parambody) throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String amountStr = URLDecoder.decode(request.getParameter("amount"), "UTF-8");
		String reference = URLDecoder.decode(request.getParameter("reference"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		String timestamp = URLDecoder.decode(request.getParameter("timestamp"), "UTF-8");
		String roundDetails = URLDecoder.decode(request.getParameter("roundDetails"), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::bonusWin:::";
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {

				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// 회원정보
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			double amount = Double.parseDouble(amountStr);
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();

			HashMap tranParam = new HashMap();

			String refId = siteId + reference;

			tranParam.put("tranId", refId);
			tranParam.put("refId", refId);
			tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			tranParam.put("siteId", siteId);
			tranParam.put("completed", true);
			tranParam.put("memberIdx", member.getMemberIdx());
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", "SLOT");
			tranParam.put("vendorIdx", 17);
			tranParam.put("vendorCode", "pragmatic");
			tranParam.put("vendorTranKey", reference);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", "");
			tranParam.put("gameIdx", providerId);

			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", "dfngtnslt_est88");
			tranParam.put("isTransfer", IS_TRANSFER);	

		
			org.codehaus.jettison.json.JSONObject debit = new org.codehaus.jettison.json.JSONObject();
			double fakeAmount = amount;// *100;
			debit.put("betId", refId);
			debit.put("tranId", siteId + reference);

			debit.put("userId", member.getMemberId());
			debit.put("vendorIdx", 17);
			debit.put("vendorKey", "S02");
			debit.put("vendor", "pragmatic");
			debit.put("gameIdx", 1);
			debit.put("gameKey", "");
			debit.put("gameType", "slot");
			debit.put("gameId", "");
			debit.put("tranType", "credit");
			debit.put("debit", 0);
			debit.put("credit", fakeAmount);
			debit.put("isCancel", 0);
			debit.put("isBonus", 1);
			debit.put("decYn", "Y");

			
			if (IS_TRANSFER.equals("N")) {
				siteService.commonBetinsert(tranParam);
	
				org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();
				cbResData = callBackService.changeBalanceSlot("PRAGMATIC SEAMLESS BONUS - ", siteApiInfo, debit);
					
				
				if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
					if(cbResData.getLong("result_code") == 0) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
	
				} else {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}else {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(siteId + reference);
				if(cntTr == 0) {
					siteService.commonBetinsert(tranParam);
				}
				try {
					double balance = 0L;	
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
					
					double afBalance = balance + amount;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", (double)afBalance);
					tranParam.put("preBalance", (double)balance);
					if(cntTr == 0) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					if(cntTr == 0) {
						resData.put("cash", afBalance);
					}else{
						resData.put("cash", balance);
					}
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");					
				
					if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
						debit.put("balance", afBalance);
						asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC TRANSFER BONUS - ", siteApiInfo, debit);
					}
					

				}catch(Exception e) {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::bonusWin:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");
		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/PromoWin")
	public @ResponseBody JSONObject promoWin(HttpServletRequest request,
			@RequestBody(required = false) String parambody) throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String amountStr = URLDecoder.decode(request.getParameter("amount"), "UTF-8");
		String reference = URLDecoder.decode(request.getParameter("reference"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		String timestamp = URLDecoder.decode(request.getParameter("timestamp"), "UTF-8");
		String roundId = URLDecoder.decode(request.getParameter("roundId"), "UTF-8");
		String gameId = URLDecoder.decode(request.getParameter("gameId "), "UTF-8");
		String campaignId = URLDecoder.decode(request.getParameter("campaignId"), "UTF-8");
		String campaignType = URLDecoder.decode(request.getParameter("campaignType "), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::promoWin:::";
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// 회원정보
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			double amount = Double.parseDouble(amountStr);
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();

			int vendorIdx = 17;
			String vendorKey = "S02";
			String vendorCetegory = "SLOT";
			if (!(gameId.startsWith("vs") || gameId.startsWith("cs"))) {
				vendorIdx = 2;
				vendorKey = "C02";
				vendorCetegory = "CASINO";
			}

			HashMap tranParam = new HashMap();

			String refId = siteId + reference;

			tranParam.put("tranId", refId);
			tranParam.put("refId", refId);
			tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			tranParam.put("siteId", siteId);
			tranParam.put("completed", true);
			tranParam.put("memberIdx", member.getMemberIdx());
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", vendorCetegory);
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pragmatic");
			tranParam.put("vendorTranKey", reference);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", providerId);

			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", "dfngtnslt_est88");
			tranParam.put("isTransfer", IS_TRANSFER);	

			org.codehaus.jettison.json.JSONObject debit = new org.codehaus.jettison.json.JSONObject();
			double fakeAmount = amount;// *100;
			debit.put("betId", refId);
			debit.put("tranId", siteId + reference);

			debit.put("userId", member.getMemberId());
			debit.put("vendorIdx", vendorIdx);
			debit.put("vendorKey", vendorKey);
			debit.put("vendor", "pragmatic");
			debit.put("gameIdx", 1);
			debit.put("gameKey", gameId);
			debit.put("gameType", "slot");
			debit.put("gameId", gameId);
			debit.put("tranType", "credit");
			debit.put("debit", 0);
			debit.put("credit", fakeAmount);
			debit.put("isCancel", 0);
			debit.put("isBonus", 1);
			debit.put("decYn", "Y");
			
			if (IS_TRANSFER.equals("N")) {
				siteService.commonBetinsert(tranParam);
				org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();		
				if (vendorCetegory.equals("SLOT")) {
					cbResData = callBackService.changeBalanceSlot("PRAGMATIC PromoWin - ", siteApiInfo, debit);
				} else {
					cbResData = callBackService.changeBalance("PRAGMATIC PromoWin - ", siteApiInfo, debit);
				}		
				if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
					if (cbResData.getLong("result_code") == 0) {
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
				} else {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			
			}else {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(siteId + reference);
				if(cntTr == 0) {					
					siteService.commonBetinsert(tranParam);
				}
				try {
					double balance = 0L;	
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
					
					double afBalance = balance + amount;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", (double)afBalance);
					tranParam.put("preBalance", (double)balance);
					if(cntTr == 0) {		
						int res = siteService.updateCbApi(tranParam);
					}
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					if(cntTr == 0) {		
						resData.put("cash", afBalance);
					}else {
						resData.put("cash", balance);
					}
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");					
				
					if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
						debit.put("balance", afBalance);
						if(vendorCetegory.equals("SLOT")) {
							asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC TRANSFER PromoWin - ", siteApiInfo, debit);
						} else {
							asyncCallBackService.asyncChangeBalance("PRAGMATIC TRANSFER PromoWin - ", siteApiInfo, debit);
						}
					}
					

				}catch(Exception e) {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::promoWin:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");

		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/JackpotWin")
	public @ResponseBody JSONObject jackpotWin(HttpServletRequest request,
			@RequestBody(required = false) String parambody) throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String gameId = URLDecoder.decode(request.getParameter("gameId"), "UTF-8");
		String roundId = URLDecoder.decode(request.getParameter("roundId"), "UTF-8");
		String jackpotId = URLDecoder.decode(request.getParameter("jackpotId"), "UTF-8");
		String amountStr = URLDecoder.decode(request.getParameter("amount"), "UTF-8");
		String reference = URLDecoder.decode(request.getParameter("reference"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");
		String timestamp = URLDecoder.decode(request.getParameter("timestamp"), "UTF-8");
		String roundDetails = URLDecoder.decode(request.getParameter("roundDetails"), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::jackpotWin:::";
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {

				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// 회원정보
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			double amount = Double.parseDouble(amountStr);
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();
			
			int vendorIdx = 17;
			String vendorKey = "S02";
			String vendorCetegory = "SLOT";
			if (!(gameId.startsWith("vs") || gameId.startsWith("cs"))) {
				vendorIdx = 2;
				vendorKey = "C02";
				vendorCetegory = "CASINO";
			}

			HashMap tranParam = new HashMap();

			String refId = siteId + roundId;

			tranParam.put("tranId", siteId + jackpotId + "#J");
			tranParam.put("refId", refId);
			tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			tranParam.put("siteId", siteId);
			tranParam.put("completed", true);
			tranParam.put("memberIdx", member.getMemberIdx());
			tranParam.put("memberId", memberId);
			tranParam.put("vendorCetegory", vendorCetegory);
			tranParam.put("vendorIdx", vendorIdx);
			tranParam.put("vendorCode", "pragmatic");
			tranParam.put("vendorTranKey", reference);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", gameId);
			tranParam.put("gameIdx", providerId);

			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt", "0");
			tranParam.put("creditAmt", amount);
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", "dfngtnslt_est88");
			tranParam.put("isTransfer", IS_TRANSFER);	

			org.codehaus.jettison.json.JSONObject debit = new org.codehaus.jettison.json.JSONObject();
			double fakeAmount = amount;// *100;
			debit.put("betId", refId);
			debit.put("tranId", siteId + jackpotId + "#J");

			debit.put("userId", member.getMemberId());
			debit.put("vendorIdx", vendorIdx);
			debit.put("vendorKey", vendorKey);
			debit.put("vendor", "pragmatic");
			debit.put("gameIdx", 1);
			debit.put("gameKey", gameId);
			debit.put("gameType", "slot");
			debit.put("gameId", gameId);
			debit.put("tranType", "credit");
			debit.put("debit", 0);
			debit.put("credit", fakeAmount);
			debit.put("isCancel", 0);
			debit.put("isBonus", 1);
			debit.put("decYn", "Y");
			
			if (IS_TRANSFER.equals("N")) {
				siteService.commonBetinsert(tranParam);
				org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();		
				if (vendorCetegory.equals("SLOT")) {
					cbResData = callBackService.changeBalanceSlot("PRAGMATIC JackpotWin - ", siteApiInfo, debit);
				} else {
					cbResData = callBackService.changeBalance("PRAGMATIC JackpotWin - ", siteApiInfo, debit);
				}		
				
				if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
					if (cbResData.getLong("result_code") == 0) {
						int res = siteService.updateCbApi(tranParam);
					}
	
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
				} else {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}else {
				// tranId 중복체크
				int cntTr = siteService.getTranIdCheck2(siteId + jackpotId + "#J");
				if(cntTr == 0) {					
					siteService.commonBetinsert(tranParam);
				}
				try {
					double balance = 0L;	
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
					
					double afBalance = balance + amount;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
					tranParam.put("balance", (long)afBalance);
					tranParam.put("preBalance", (long)balance);
					if(cntTr == 0) {			
						int res = siteService.updateCbApi(tranParam);
					}
	
					resData.put("transactionId", reference);
					resData.put("currency", "VND");
					if(cntTr == 0) {			
						resData.put("cash", afBalance);
					}else {
						resData.put("cash", balance);
					}
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");					
				
					if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
						debit.put("balance", afBalance);
						if(vendorCetegory.equals("SLOT")) {
							asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC TRANSFER JackpotWin - ", siteApiInfo, debit);
						} else {
							asyncCallBackService.asyncChangeBalance("PRAGMATIC TRANSFER JackpotWin - ", siteApiInfo, debit);
						}
					}
					

				}catch(Exception e) {
					resData.put("error", 120);
					resData.put("description",  "Internal Server Error(no-retry)");
				}
			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::jackpotWin:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("status", "failure");
			resData.put("balance", "0.00");
		}
		return resData;
	}

	@CrossOrigin
	@PostMapping(value = "/EndRound")
	public @ResponseBody JSONObject endRound(HttpServletRequest request,
			@RequestBody(required = false) String parambody) throws Exception {
		JSONObject resData = new JSONObject();
		String hash = URLDecoder.decode(request.getParameter("hash"), "UTF-8");
		String userId = URLDecoder.decode(request.getParameter("userId"), "UTF-8");
		String gameId = URLDecoder.decode(request.getParameter("gameId"), "UTF-8");
		String roundId = URLDecoder.decode(request.getParameter("roundId"), "UTF-8");
		String providerId = URLDecoder.decode(request.getParameter("providerId"), "UTF-8");

		try {
			HashMap sParam = new HashMap();

			sParam.put("siteIdx", Integer.parseInt(userId.substring(0, 3), 16));
			sParam.put("memberId", userId.substring(3, userId.length()));
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::endRound:::";
			HashMap siteApiInfo = siteService.getSiteApiInfo(sParam);
			String siteId = siteApiInfo.get("siteId").toString();
			log.info(LOG_PREFIX+ "# sparam() : " + siteApiInfo.toString());

			if (siteApiInfo == null) {

				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			Map authParam = new HashMap();
			authParam.put("memberId", memberId);
			authParam.put("siteId", siteId);
			authParam.put("siteIdx", siteApiInfo.get("siteIdx"));

			// 회원정보
			Member member = siteService.getMemberByToken(authParam);

			if (member == null) {
				resData.put("error", 2);
				resData.put("description", "Player not found or logged out.");
				return resData;
			}

			// 크레딧 정보가 없는경우 체크
			BetParam betCheckParam = new BetParam();
			betCheckParam.setBetId(siteId + roundId);
			HashMap betCheck = siteService.getBetCheck(betCheckParam);

			int vendorIdx = 17;
			String vendorKey = "S02";
			String vendorCetegory = "SLOT";
			if (!(gameId.startsWith("vs") || gameId.startsWith("cs"))) {
				vendorIdx = 2;
				vendorKey = "C02";
				vendorCetegory = "CASINO";
			}
			
			
			final String IS_TRANSFER = siteApiInfo.get("isTransfer").toString();

			if (Integer.parseInt(betCheck.get("credit").toString()) == 0) {

				HashMap tranParam = new HashMap();

				String refId = siteId + roundId;

				tranParam.put("tranId", siteId + roundId + "#CLOSE");
				tranParam.put("refId", refId);
				tranParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				tranParam.put("siteId", siteId);
				tranParam.put("completed", true);
				tranParam.put("memberIdx", member.getMemberIdx());
				tranParam.put("memberId", memberId);
				tranParam.put("vendorCetegory", vendorCetegory);
				tranParam.put("vendorIdx", vendorIdx);
				tranParam.put("vendorCode", "pragmatic");
				tranParam.put("vendorTranKey", roundId + "#CLOSE");
				tranParam.put("gameType", "slot");
				tranParam.put("gameId", gameId);
				tranParam.put("gameIdx", gameId);

				tranParam.put("tranType", "credit");
				tranParam.put("depositAmt", "0");
				tranParam.put("creditAmt", "0");
				tranParam.put("isCancel", "N");
				tranParam.put("isTie", "N");
				tranParam.put("apiStatus", 0);
				tranParam.put("vendorApiId", "dfngtnslt_est88");
				tranParam.put("isTransfer", IS_TRANSFER);	
			
				
				org.codehaus.jettison.json.JSONObject debit = new org.codehaus.jettison.json.JSONObject();

				debit.put("betId", refId);
				debit.put("tranId", siteId + roundId + "#CLOSE");

				debit.put("userId", member.getMemberId());
				debit.put("vendorIdx", vendorIdx);
				debit.put("vendorKey", vendorKey);
				debit.put("vendor", "pragmatic");
				debit.put("gameIdx", 1);
				debit.put("gameKey", gameId);
				debit.put("gameType", "slot");
				debit.put("gameId", gameId);
				debit.put("tranType", "credit");
				debit.put("debit", 0);
				debit.put("credit", 0);
				debit.put("isCancel", 0);
				debit.put("isBonus", 1);
				debit.put("decYn", "Y");
				
				if (IS_TRANSFER.equals("N")) {
					siteService.commonBetinsert(tranParam);
					
					org.codehaus.jettison.json.JSONObject cbResData = new org.codehaus.jettison.json.JSONObject();		
					if (vendorCetegory.equals("SLOT")) {
						cbResData = callBackService.changeBalanceSlot("PRAGMATIC ENDGame - ", siteApiInfo, debit);
					} else {
						cbResData = callBackService.changeBalance("PRAGMATIC ENDGame - ", siteApiInfo, debit);
					}		
					
	
					if (cbResData.getLong("result_code") == 0 || cbResData.getLong("result_code") == 98) {
						log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
						tranParam.put("balance", Double.parseDouble(cbResData.getString("balance")));
						if (cbResData.getLong("result_code") == 0 ) {
							int res = siteService.updateCbApi(tranParam);
						}
	
						resData.put("cash", Double.parseDouble(cbResData.getString("balance")));
						resData.put("bonus", 0);
						resData.put("error", 0);
						resData.put("description", "Success");
					}
				}else {
					
					// tranId 중복체크
					int cntTr = siteService.getTranIdCheck2(siteId + roundId + "#CLOSE");
					if(cntTr ==0) {
						siteService.commonBetinsert(tranParam);
					}
					try {
						double balance = 0L;	
						HashMap balanceMap = new HashMap<>();
						balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
						balanceMap.put("memberId", memberId);
						balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
						
						double afBalance = balance;
						log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
						tranParam.put("balance", (long)afBalance);
						tranParam.put("preBalance", (long)balance);
						if(cntTr ==0) {
							int res = siteService.updateCbApi(tranParam);
						}
						if(cntTr ==0) {
							resData.put("cash", afBalance);
						}else {
							resData.put("cash", balance);
						}
						
						resData.put("bonus", 0);
						resData.put("error", 0);
						resData.put("description", "Success");					
					
						if(siteApiInfo.get("siteCbUrl") != null && !"".equals(siteApiInfo.get("siteCbUrl").toString())) {
							debit.put("balance", afBalance);
							if(vendorCetegory.equals("SLOT")) {
								asyncCallBackService.asyncChangeBalanceSlot("PRAGMATIC TRANSFER ENDGame - ", siteApiInfo, debit);
							} else {
								asyncCallBackService.asyncChangeBalance("PRAGMATIC TRANSFER ENDGame - ", siteApiInfo, debit);
							}
						}
						

					}catch(Exception e) {
						resData.put("error", 120);
						resData.put("description",  "Internal Server Error(no-retry)");
					}
				}
			} else {
				if (IS_TRANSFER.equals("N")) {
					double balance = getBalanceDouble(LOG_PREFIX, siteApiInfo.get("siteCbUrl").toString(), memberId);
					resData.put("cash", balance);
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");
					
				}else {
					
					double balance = 0L;	
					HashMap balanceMap = new HashMap<>();
					balanceMap.put("siteIdx", siteApiInfo.get("siteIdx"));
					balanceMap.put("memberId", memberId);
					balance = Double.parseDouble("" + siteService.getUserBalance(balanceMap));
					
					double afBalance = balance;
					log.info(LOG_PREFIX+ "siteService.updateCbApi(tranParam)");
						
					resData.put("cash", afBalance);
					resData.put("bonus", 0);
					resData.put("error", 0);
					resData.put("description", "Success");					
				
				}

			}

		} catch (Exception e) {
			String memberId = userId.substring(3, userId.length());
			final String LOG_PREFIX = "#-CB::PP::"+memberId+"::endRound:::";
			log.error(LOG_PREFIX+ e.toString());
			resData.put("error", 120);
			resData.put("description",  "Internal Server Error(no-retry)");
		}
		return resData;
	}

	private org.codehaus.jettison.json.JSONObject getBalance(String LOG_PREFIX, HashMap siteApiInfo, JSONObject member)
			throws JSONException {

		org.codehaus.jettison.json.JSONObject res = new org.codehaus.jettison.json.JSONObject();

		log.info(LOG_PREFIX+ "# site.getSiteCbUrl() : " + siteApiInfo.get("siteCbUrl") + "/balance");
		log.info(LOG_PREFIX+ "# site.getSiteCbUrl() : " + member.toString());
		String url = siteApiInfo.get("siteCbUrl") + "/balance";
		ResponseEntity<String> responseEntity = null;
		try {
		    responseEntity = webClient.post()
			    .uri(url)
			    .header("Content-Type", "application/json")
			    .header("Accept", "application/json")
			    .header("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(LOG_PREFIX+ "status code : {}", responseEntity != null ? responseEntity.getStatusCode() : "NULL");
		    log.info(LOG_PREFIX+ "body: {}", responseEntity != null ? responseEntity.getBody() : "");

		} catch (Exception ex) {
		    log.error(LOG_PREFIX+ "error calling site cb /balance", ex);
		    throw ex;
		}

		org.codehaus.jettison.json.JSONObject resData = new org.codehaus.jettison.json.JSONObject(
			responseEntity != null ? responseEntity.getBody() : "{}");

		return resData;

	}

	private double getBalanceDouble(String LOG_PREFIX, String cbUrl, String memId) {
		double balance = 0L;
		try {

			log.info(LOG_PREFIX+ "balance: {}", cbUrl + "/balance");

			JSONObject members = new JSONObject();
			members.put("userId", memId);
			members.put("decYn", "Y");

			    // 회원 머니
			    ResponseEntity<String> responseEntity = null;
			    try {
				responseEntity = webClient.post()
					.uri(cbUrl + "/balance")
					.header("Content-Type", "application/json")
					.header("Accept", "application/json")
					.header("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(members.toString())
					.retrieve()
					.toEntity(String.class)
					.block();

				log.info(LOG_PREFIX+ "status code : {}", responseEntity != null ? responseEntity.getStatusCode() : "NULL");
				log.info(LOG_PREFIX+ "body: {}", responseEntity != null ? responseEntity.getBody() : "");

				org.codehaus.jettison.json.JSONObject resData = new org.codehaus.jettison.json.JSONObject(
					responseEntity != null ? responseEntity.getBody() : "{}");
				balance = Double.parseDouble(resData.getString("balance")); // 문자열이어도 안전("balance");// * 0.01;

			    } catch (Exception e) {
				log.error(LOG_PREFIX+ "error calling cb balance", e);
				throw e;
			    }
		} catch (Exception e) {

		}
		return balance;

	}

	private String makeApiKey(String param) {

		int n = 20; // n자리 쿠폰
		char[] chs = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
				'J', 'K', 'L', 'M', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'N', 'O', 'P', 'Q',
				'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
				'z' };

		Random rd = new Random();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < n; i++) {
			char ch = chs[rd.nextInt(chs.length)];
			sb.append(ch);
		}
		return param + sb.toString();

	}

}
