package com.bb.front;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Random;

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.bb.jwt.JwtManager;
import com.bb.service.CallBackService;
import com.bb.service.SiteService;

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

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

	@Autowired
	private final JwtManager jwtManager;

	@Autowired
	SiteService siteService;

	@Autowired
	CallBackService callBackService;



	@GetMapping(value = "/api/balance" )
	public @ResponseBody String balance(HttpServletRequest request, ModelMap model) throws Exception {

		 String userId = request.getParameter("user_id");
		int siteIdx = Integer.parseInt(userId.substring(0, 3), 16);
		String memberId = userId.substring(3, userId.length());
		String authorization = request.getHeader("Authorization").toString();
		final String LOG_PREFIX = "#-CB::tower::"+memberId+"::balance:::";
		log.info("#callback::tower::"+ "SITE_IDX: "+siteIdx+", USER INFO: " + memberId);


		//사이트정보
		HashMap sParam = new HashMap();
		sParam.put("siteIdx", siteIdx);
		sParam.put("memberId", memberId);
		sParam.put("vendor", "tower");
		sParam.put("callbackKey", authorization);

		HashMap<String,String> siteApiInfo = siteService.getSiteApiInfoByCallbackKey(sParam);

		if(siteApiInfo == null) {
			log.error(LOG_PREFIX+ "Callback Key 불일치");

			return "E1";
		}

		if(siteApiInfo.get("memberIdx") == null) {
			log.error(LOG_PREFIX+ "존재하지 않는 회원");
			return "E2";
		}

		org.codehaus.jettison.json.JSONObject member = new org.codehaus.jettison.json.JSONObject();
		member.put("userId", memberId);
		org.codehaus.jettison.json.JSONObject resData  = callBackService.getBalance(siteApiInfo, member);
		if(resData == null) {
			log.error(LOG_PREFIX+ "BALANCE_CALLBACK_ERROR");
			return "E3";
		}
		String balance = resData.getString("balance");


		try {

		}catch(Exception e) {
			log.error(LOG_PREFIX + "ERROR {}", e.toString());
		}
		log.info(LOG_PREFIX+ "balance {}", balance);
		return balance;
	}


	@GetMapping(value = "/api/bet" )
	public @ResponseBody JSONObject bet(HttpServletRequest request, ModelMap model) throws Exception {

		JSONObject res = new JSONObject();
		 // 회원ID
        String userId = request.getParameter("user_id");


		int siteIdx = Integer.parseInt(userId.substring(0, 3), 16);
		String memberId = userId.substring(3, userId.length());
		String authorization = request.getHeader("Authorization").toString();
		final String LOG_PREFIX = "#-CB::tower::"+memberId+"::"+request.getParameter("transaction_id")+"::BET:::";
		log.info(LOG_PREFIX+ "#callback::tower::"+ "SITE_IDX: "+siteIdx+", USER INFO: " + memberId);
		log.info(LOG_PREFIX+ "request: " + request.toString());


		//사이트정보
		HashMap sParam = new HashMap();
		sParam.put("siteIdx", siteIdx);
		sParam.put("memberId", memberId);
		sParam.put("vendor", "tower");
		sParam.put("callbackKey", authorization);
		/*
		 * CAST(si.siteIdx AS CHAR) AS siteIdx,
			si.siteId,
			CAST(sm.memberIdx AS CHAR) AS memberIdx,
			sm.memberId,
			si.siteCbUrl,
			IFNULL(sa.vendorApiId, vi.vendorApiId)  AS vendorApiId
		 */

		HashMap<String,String> siteApiInfo = siteService.getSiteApiInfoByCallbackKey(sParam);

		if(siteApiInfo == null) {
			log.error(LOG_PREFIX+ "Callback Key 불일치");
			res.put("status", "error")	;
			return res;
		}

		if(siteApiInfo.get("memberIdx") == null) {
			log.error(LOG_PREFIX+ "존재하지 않는 회원");
			res.put("status", "error")	;
			return res;
		}


		sParam.put("vendorGameCode", request.getParameter("vendorCode"));
		log.info(LOG_PREFIX + "getSiteVendorInfo::"+sParam.toString());
		HashMap<String,String> siteVendorInfo = siteService.getSiteVendorInfo(sParam);
		if(siteVendorInfo.get("vendorIdx") == null) {
			log.error(LOG_PREFIX+ "존재하지 않는 벤더코드");
			res.put("status", "error")	;
			return res;
		}


        // 배팅의 고유ID
        String transactionId = request.getParameter("transaction_id");

        // 게임ID (optional)
        String gameId = request.getParameter("game_id");

        // 벤더코드
        String vendorCode = request.getParameter("vendorCode");

        // 게임코드
        String gameCode = request.getParameter("gameCode");

        // 게임타이틀
        String gameTitle = gameCode;
        Enumeration params = request.getParameterNames();
    	while (params.hasMoreElements()) {
    	    String paramName = (String) params.nextElement();
    	    if(paramName.equals("gameTitle")) {
    	    	gameTitle = request.getParameter(paramName);
    	    }
    	}


        // 배팅액
        String amountS = request.getParameter("amount");
        long amount = 0;
        Double rrr = Double.parseDouble(amountS);
        amount = rrr.longValue();

		try {

			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();

			long siteCredit = Long.parseLong(siteVendorInfo.get("credit").toString());
			if(siteCredit < amount) {
				log.error(LOG_PREFIX+ "NO_SITE_CREDIT");
				res.put("status", "error")	;
				return res;
			}

			// 최대 베팅 금액 처리 (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 - finalMaxBet: " + finalMaxBet);
				res.put("status", "error")	;
				return res;
			}

			String vendorTranKey = transactionId;
			String tranId = transactionId;
			String betId = transactionId;
			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			int vendorIdx = Integer.parseInt(siteVendorInfo.get("vendorIdx").toString());
			String vendorCetegory = siteVendorInfo.get("vendorCetegory").toString();
			String gameName = gameTitle;

			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", "tower");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", gameCode);
			tranParam.put("gameIdx", gameName);
			tranParam.put("tranType", "debit");
			tranParam.put("depositAmt", amount);
			tranParam.put("creditAmt", "0");
			tranParam.put("isCancel", "N");
			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			log.info(LOG_PREFIX + "-----INSERT_BET_START-----");
			siteService.commonBetinsert(tranParam);
			log.info(LOG_PREFIX + "-----INSERT_BET_END-----");

			org.codehaus.jettison.json.JSONObject callBackObj = new org.codehaus.jettison.json.JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "tower");
			callBackObj.put("gameIdx", vendorIdx);
			callBackObj.put("gameKey", gameName);
			callBackObj.put("gameId", gameCode);
			callBackObj.put("gameType", "slot");
			callBackObj.put("tranType", "debit");
			callBackObj.put("debit", amount);
			callBackObj.put("credit", 0);
			callBackObj.put("isCancel", 0);
			callBackObj.put("isBonus", 0);
			// callBackObj.put("requestAt", betDateTimeStr);
			log.info(LOG_PREFIX + "SEND_BET request body: " + callBackObj.toString());
			org.codehaus.jettison.json.JSONObject resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
			log.info(LOG_PREFIX + "SEND_BET status code: " + resData.getLong("result_code"));
			log.info(LOG_PREFIX + "SEND_BET response body: " + resData.toString());

			if(resData.getLong("result_code") == 0) {
				tranParam.put("balance", resData.getInt("balance"));
				int rescreditUpdate = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");

				String balance = resData.getString("balance");
				res.put("status", "OK");
				res.put("balance", balance);


			} else if(resData.getLong("result_code") == 98) {
				String balance = resData.getString("balance");
				res.put("status", "OK");
				res.put("balance", balance);
			} else if(resData.getLong("result_code") == 80) {
				String balance = resData.getString("balance");
				res.put("status", "error");
				res.put("balance", balance);
			} else {
				res.put("status", "error");
			}



			log.info("res {}", res);
		}catch(Exception e) {
			log.error(LOG_PREFIX + "ERROR: " + e.toString());
		}
		return res;
	}


	@GetMapping(value = "/api/result" )
	public @ResponseBody JSONObject  result(HttpServletRequest request, ModelMap model) throws Exception {

		JSONObject res = new JSONObject();
		// 회원ID
        String userId = request.getParameter("user_id");

        // 거래 유형
        String transactionType = request.getParameter("transaction_type");

        // 배팅의 고유ID
        String transactionId = request.getParameter("transaction_id");

        // 게임ID (optional)
        String gameId = request.getParameter("game_id");

        // 벤더코드
        String vendorCode = request.getParameter("vendorCode");

        // 게임코드
        String gameCode = request.getParameter("gameCode");

        // 게임타이틀
        String gameTitle = gameCode;
        Enumeration params = request.getParameterNames();
    	while (params.hasMoreElements()) {
    	    String paramName = (String) params.nextElement();
    	    if(paramName.equals("gameTitle")) {
    	    	gameTitle = request.getParameter(paramName);
    	    }
    	}

        // 금액
        String amountS = request.getParameter("amount");
        long amount = 0;
        Double rrr = Double.parseDouble(amountS);
        amount = rrr.longValue();

        // 거래의 고유ID
        String reference = request.getParameter("reference");

        // 취소할 reference (CANCEL_WIN 시에만 전송)
        String referenceForCancel = request.getParameter("reference_for_cancel");

        // 배팅상세내역 JSON (optional)
        String bettingData = request.getParameter("betting_data");


        int siteIdx = Integer.parseInt(userId.substring(0, 3), 16);
		String memberId = userId.substring(3, userId.length());
		String authorization = request.getHeader("Authorization").toString();
		final String LOG_PREFIX = "#-CB::tower::"+memberId+"::"+request.getParameter("transaction_id")+"::RESULT:::";
		log.info(LOG_PREFIX+ "#callback::tower::"+ "SITE_IDX: "+siteIdx+", USER INFO: " + memberId);
		log.info(LOG_PREFIX+ "request: " + request.toString());


		//사이트정보
		HashMap sParam = new HashMap();
		sParam.put("siteIdx", siteIdx);
		sParam.put("memberId", memberId);
		sParam.put("vendor", "tower");
		sParam.put("callbackKey", authorization);
		/*
		 * CAST(si.siteIdx AS CHAR) AS siteIdx,
			si.siteId,
			CAST(sm.memberIdx AS CHAR) AS memberIdx,
			sm.memberId,
			si.siteCbUrl,
			IFNULL(sa.vendorApiId, vi.vendorApiId)  AS vendorApiId
		 */

		HashMap<String,String> siteApiInfo = siteService.getSiteApiInfoByCallbackKey(sParam);

		if(siteApiInfo == null) {
			log.error(LOG_PREFIX+ "Callback Key 불일치");
			res.put("status", "error")	;
			return res;
		}

		if(siteApiInfo.get("memberIdx") == null) {
			log.error(LOG_PREFIX+ "존재하지 않는 회원");
			res.put("status", "error")	;
			return res;
		}


		sParam.put("vendorGameCode", request.getParameter("vendorCode"));
		log.info(LOG_PREFIX + "getSiteVendorInfo::"+sParam.toString());
		HashMap<String,String> siteVendorInfo = siteService.getSiteVendorInfo(sParam);
		if(siteVendorInfo.get("vendorIdx") == null) {
			log.error(LOG_PREFIX+ "존재하지 않는 벤더코드");
			res.put("status", "error")	;
			return res;
		}


		try {

			String siteId = siteVendorInfo.get("siteId").toString();
			long memberIdx = Long.parseLong(siteVendorInfo.get("memberIdx").toString());
			String vendorApiId = siteVendorInfo.get("vendorApiId").toString();


			String vendorTranKey = transactionId+transactionType;
			String tranId = transactionId +transactionType;
			String betId = transactionId;

			if(reference != null && !"".equals(reference)) {
				// betId = reference;
			}

			String vendorKey = siteVendorInfo.get("vendorKey").toString();
			int vendorIdx = Integer.parseInt(siteVendorInfo.get("vendorIdx").toString());
			String vendorCetegory = siteVendorInfo.get("vendorCetegory").toString();
			String gameName = gameTitle;

			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", "tower");
			tranParam.put("vendorTranKey", vendorTranKey);
			tranParam.put("gameType", "slot");
			tranParam.put("gameId", gameCode);
			tranParam.put("gameIdx", gameName);
			tranParam.put("tranType", "credit");
			tranParam.put("depositAmt","0" );
			tranParam.put("creditAmt", amount);

			if("CANCEL".equals(transactionType) || "CANCEL_WIN".equals(transactionType)) {
				tranParam.put("isCancel", "Y");
			}else {
				tranParam.put("isCancel", "N");
			}

			tranParam.put("isTie", "N");
			tranParam.put("apiStatus", 0);
			tranParam.put("vendorApiId", vendorApiId);
			log.info(LOG_PREFIX + "-----INSERT_RESULT_START-----");
			siteService.commonBetinsert(tranParam);
			log.info(LOG_PREFIX + "-----INSERT_RESULT_END-----");

			org.codehaus.jettison.json.JSONObject callBackObj = new org.codehaus.jettison.json.JSONObject();
			callBackObj.put("betId", betId);
			callBackObj.put("tranId", tranId);
			callBackObj.put("userId", memberId);
			callBackObj.put("vendorIdx", vendorIdx);
			callBackObj.put("vendorKey", vendorKey);
			callBackObj.put("vendor", "tower");
			callBackObj.put("gameIdx", vendorIdx);
			callBackObj.put("gameKey", gameName);
			callBackObj.put("gameId", gameCode);
			callBackObj.put("gameType", "slot");
			callBackObj.put("tranType", "credit");
			callBackObj.put("debit",0 );
			callBackObj.put("credit", amount);
			if("CANCEL".equals(transactionType) || "CANCEL_WIN".equals(transactionType)) {
				callBackObj.put("isCancel", 1);
			}else {
				callBackObj.put("isCancel", 0);
			}
			if("PROMO_WIN".equals(transactionType) ) {
				callBackObj.put("isBonus", 1);
			}else {
				callBackObj.put("isBonus", 0);
			}
			// callBackObj.put("requestAt", betDateTimeStr);
			log.info(LOG_PREFIX + "SEND_RESULT request body: " + callBackObj.toString());
			org.codehaus.jettison.json.JSONObject resData = callBackService.changeBalanceSlot(LOG_PREFIX, siteVendorInfo, callBackObj);
			log.info(LOG_PREFIX + "SEND_RESULT status code: " + resData.getLong("result_code"));
			log.info(LOG_PREFIX + "SEND_RESULT response body: " + resData.toString());

			if(resData.getLong("result_code") == 0) {
				tranParam.put("balance", resData.getInt("balance"));
				int rescreditUpdate = siteService.updateCbApi(tranParam);
				log.info(LOG_PREFIX + "UPDATE_CALLBACK_API_STATUS END");

				String balance = resData.getString("balance");
				res.put("status", "OK");
				res.put("balance", balance);


			} else if(resData.getLong("result_code") == 98) {
				String balance = resData.getString("balance");
				res.put("status", "OK");
				res.put("balance", balance);
			} else if(resData.getLong("result_code") == 80) {
				String balance = resData.getString("balance");
				res.put("status", "error");
				res.put("balance", balance);
			} else {
				res.put("status", "error");
			}



			log.info("res {}", res);
		}catch(Exception e) {
			log.error(LOG_PREFIX + "ERROR: " + e.toString());
		}
		return res;
	}



	 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();


	  }


}

