package com.bb.service;

import java.util.HashMap;

import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientRequestException;

import com.bb.dao.CallBackDao;
import com.bb.util.StringUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CallBackServiceImpl implements CallBackService {

	@Autowired
	private CallBackDao callBackDao;

	@Autowired
	private WebClient webClient; // Inject WebClient

	@Override
	public JSONObject getBalance(HashMap siteApiInfo, JSONObject parammember) {

		JSONObject res = new JSONObject();
		String siteId = siteApiInfo.get("siteId").toString();
		String memberId = siteApiInfo.get("memberId").toString();

		HttpHeaders header = new HttpHeaders();
		header.set("Connection", "close");
		header.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
		header.add("Accept", MediaType.APPLICATION_JSON_VALUE);
		header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
				+ " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");

		long startTimestamp = System.currentTimeMillis();
		final String LOG_PREFIX = "#-CMM::CB::getBalance::" + siteId + "::" + memberId + "::" + startTimestamp + ":::";
		final String baseCbUrl = siteApiInfo.get("siteCbUrl").toString().trim();

		try {
			parammember.put("requestAt", Long.toString(startTimestamp));
			log.info(LOG_PREFIX + "Callback URL: " + baseCbUrl + "/balance");
			log.info(LOG_PREFIX + "Body: " + parammember.toString());

			/*
			ResponseEntity<String> responseEntity = webClient.post()
												            .uri(baseCbUrl + "/balance")
												            .headers(h -> h.addAll(header))
												            .bodyValue(parammember.toString())
												            .retrieve()
												            .onStatus(HttpStatusCode::isError, resp -> {
												                // 에러 상태 코드 처리 (선택사항)
												                return resp.bodyToMono(String.class)
												                    .flatMap(body -> Mono.error(new RuntimeException("HTTP " + resp.statusCode() + " " + body)));
												            })
												            .toEntity(String.class)
												            .block();
			 */

			ResponseEntity<String> responseEntity = webClient.post().uri(baseCbUrl + "/balance")
					.headers(h -> h.addAll(header)).bodyValue(parammember.toString())
					.exchangeToMono(resp -> resp.toEntity(String.class)).block();

			int statusCode = responseEntity.getStatusCode().value();
			String responseBody = responseEntity.getBody();

			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산

			log.info(LOG_PREFIX + "Response HTTP Status: " + statusCode);
			log.info(LOG_PREFIX + "Response Body: " + responseBody);

			if (responseBody == null || responseBody.isEmpty()) {
				log.error(LOG_PREFIX + "Received empty or null response body from WebClient.");
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
				logParam.put("vendorIdx", null);
				logParam.put("statusCode", statusCode); // Use actual HTTP status code
				logParam.put("callBackType", "balance");
				logParam.put("callBackReqBody", parammember.toString());
				logParam.put("callBackResBody", "Empty or null response body");
				logParam.put("errorCode", "EMPTY_RESPONSE");
				logParam.put("errorMsg", "WebClient returned empty or null body for /balance");
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", System.currentTimeMillis());
				callBackDao.insertCallBackErrLog(logParam);
				return null;
			}

			if (statusCode == 200) {
				int resultCode = 0;
				res = new JSONObject(responseBody);

				if (res.has("result_code")) {
					resultCode = res.getInt("result_code");
				} else {
					try {
						resultCode = res.getInt("resultCode");
					} catch (Exception e) {
						resultCode = -9;
					}
				}

				if (diffTime < -1.8) {
					log.error(LOG_PREFIX + "잔액요청 응답시간(1.8초) 초과");
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
					logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
					logParam.put("vendorIdx", null);
					logParam.put("statusCode", resultCode);
					logParam.put("callBackType", "balance");
					logParam.put("callBackReqBody", parammember.toString());
					logParam.put("callBackResBody", res.toString());
					logParam.put("errorCode", "RESPONSE_TIME_OUT");
					logParam.put("errorMsg", "응답시간(1.8초) 초과");
					logParam.put("regDate", startTimestamp);
					logParam.put("updDate", endTimestamp);
					callBackDao.insertCallBackErrLog(logParam);

					return null;
				}

				if (resultCode != 0) {
					// 에러로그넣기
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
					logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
					logParam.put("vendorIdx", null);
					logParam.put("statusCode", resultCode);
					logParam.put("callBackType", "balance");
					logParam.put("callBackReqBody", parammember.toString());
					logParam.put("callBackResBody", res.toString());
					logParam.put("errorCode", "RESULT_CODE_ERR");
					logParam.put("errorMsg", res.toString());
					logParam.put("regDate", startTimestamp);
					logParam.put("updDate", endTimestamp);
					callBackDao.insertCallBackErrLog(logParam);
					log.info(LOG_PREFIX + "code : {}", statusCode);
					log.info(LOG_PREFIX + "body: {}", responseBody);

					return null;
				} else {

				}
			} else {
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
				logParam.put("vendorIdx", null);
				logParam.put("statusCode", statusCode);
				logParam.put("callBackType", "balance");
				logParam.put("callBackReqBody", parammember.toString());
				logParam.put("callBackResBody", StringUtils.truncateBodyForDb(responseBody, 1000));
				logParam.put("errorCode", "HTTP_STATUS_CODE_ERR");
				logParam.put("errorMsg", statusCode + " Error");
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", endTimestamp);
				callBackDao.insertCallBackErrLog(logParam);
				log.error(LOG_PREFIX + "code : {}", statusCode);
				log.error(LOG_PREFIX + "body: {}", responseBody);

				return null;
			}

		} catch (WebClientRequestException e) { // Catch WebClient specific network errors
			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산
			String errCode = "";
			String errMsg = "";

			Throwable cause = e.getCause();
			if (hasCause(cause, io.netty.channel.ConnectTimeoutException.class)
					|| hasCause(cause, java.net.ConnectException.class)) {
				log.error(LOG_PREFIX + "ConnectException e: CONNECT_TIMEOUT (3000ms)"); // WebClient config timeout is
																						// 3000ms
				log.error(LOG_PREFIX + "ConnectException e: {}", e.toString());
				errCode = "CONNECT_TIMEOUT";
				errMsg = "ConnectException e: CONNECT_TIMEOUT (3000ms)";
			} else if (hasCause(cause, io.netty.handler.timeout.ReadTimeoutException.class)
					|| hasCause(cause, java.net.SocketTimeoutException.class)) {
				log.error(LOG_PREFIX + "SocketTimeoutException e: READ_TIMEOUT (5000ms)");
				log.error(LOG_PREFIX + "SocketTimeoutException e: {}", e.toString());
				errCode = "READ_TIMEOUT";
				errMsg = "SocketTimeoutException e: READ_TIMEOUT (5000ms)";
			} else {
				log.error(LOG_PREFIX + "WebClientRequestException e: 기타 네트워크 예외 발생 발생!!!");
				log.error(LOG_PREFIX + "WebClientRequestException e: {}", e.toString());
				errCode = "NETWORK_ERROR";
				errMsg = "WebClientRequestException e: 기타 네트워크 예외 발생 발생!!!";
			}

			HashMap logParam = new HashMap();
			logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
			logParam.put("vendorIdx", null);
			logParam.put("statusCode", null);
			logParam.put("callBackType", "balance");
			logParam.put("callBackReqBody", parammember.toString());
			logParam.put("callBackResBody", baseCbUrl + "/balance" + " > 실패");
			logParam.put("errorCode", errCode);
			logParam.put("errorMsg", errMsg);
			logParam.put("regDate", startTimestamp);
			logParam.put("updDate", endTimestamp);
			callBackDao.insertCallBackErrLog(logParam);

			res = null;
		} catch (Exception e) { // General exception catch
			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산

			log.error(LOG_PREFIX + "Exception e: {}", e.toString());
			e.printStackTrace();

			HashMap logParam = new HashMap();
			logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
			logParam.put("vendorIdx", null);
			logParam.put("statusCode", null);
			logParam.put("callBackType", "balance");
			logParam.put("callBackReqBody", parammember.toString());
			logParam.put("callBackResBody", baseCbUrl + "/balance" + " > 실패");
			logParam.put("errorCode", "GENERAL_ERROR");
			logParam.put("errorMsg", "Exception e: " + e.toString());
			logParam.put("regDate", startTimestamp);
			logParam.put("updDate", endTimestamp);
			callBackDao.insertCallBackErrLog(logParam);

			res = null;
		}

		return res;
	}

	@Override
	public JSONObject changeBalance(String LOG_PREFIX, HashMap siteApiInfo, JSONObject data) {

		JSONObject res = new JSONObject();
		String siteId = siteApiInfo.get("siteId").toString();
		String memberId = siteApiInfo.get("memberId").toString();
		String tranId = "";
		final String baseCbUrl = siteApiInfo.get("siteCbUrl").toString().trim();

		try {
			tranId = data.getString("tranId");
			log.info(LOG_PREFIX + "data.has(\"isData\"): " + data.has("isData"));
			log.info(LOG_PREFIX + "data.has(\"betKey\"): " + data.has("betKey"));
			if (!data.has("isData")) {
				data.put("isData", "N");
			}
			if (!data.has("betKey")) {
				data.put("betKey", tranId);
			}
		} catch (Exception e) {
		}

		HttpHeaders header = new HttpHeaders();
		header.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
		header.add("Accept", MediaType.APPLICATION_JSON_VALUE);
		header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
				+ " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
		header.set("Connection", "close");

		// 요청시간
		long startTimestamp = System.currentTimeMillis();
		try {
			log.info(LOG_PREFIX + "Callback URL: " + baseCbUrl + "/changebalance");
			log.info(LOG_PREFIX + "Body: " + data.toString());
			/*
			ResponseEntity<String> responseEntity = webClient.post()
															.uri(baseCbUrl + "/changebalance")
															.headers(h -> h.addAll(header))
															.bodyValue(data.toString())
															.retrieve()
															.toEntity(String.class)
															.block();
			*/
			ResponseEntity<String> responseEntity = webClient.post().uri(baseCbUrl + "/changebalance")
					.headers(h -> h.addAll(header)).bodyValue(data.toString())
					.exchangeToMono(resp -> resp.toEntity(String.class)).block();

			int statusCode = responseEntity.getStatusCode().value();
			String responseBody = responseEntity.getBody(); // 정상적으로 바디 읽기 가능

			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산

			if (responseBody == null || responseBody.isEmpty()) {
				log.error(LOG_PREFIX + "Received empty or null response body from WebClient.");
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
				logParam.put("vendorIdx", data.get("vendorIdx"));
				logParam.put("statusCode", statusCode);
				logParam.put("callBackType", data.get("tranType").toString());
				logParam.put("tranId", tranId);
				logParam.put("callBackReqBody", data.toString());
				logParam.put("callBackResBody", "Empty or null response body");
				logParam.put("errorCode", "EMPTY_RESPONSE");
				logParam.put("errorMsg", "WebClient returned empty or null body for /changebalance");
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", System.currentTimeMillis());
				callBackDao.insertCallBackErrLog(logParam);

				res = new JSONObject();
				res.put("result_code", -9999);
				res.put("error_msg", "EMPTY_RESPONSE");

				return res;
			}

			if (statusCode == 200) {
				int resultCode = 0;
				res = new JSONObject(responseBody);
				if (res.has("result_code")) {
					resultCode = res.getInt("result_code");
				} else {
					try {
						resultCode = res.getInt("resultCode");
					} catch (Exception e) {
						resultCode = -9;
					}
				}

				if (diffTime < -1.8) {
					log.error(LOG_PREFIX + "응답시간(1.8초) 초과");
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
					logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
					logParam.put("vendorIdx", data.get("vendorIdx"));
					logParam.put("statusCode", resultCode);
					logParam.put("callBackType", data.get("tranType").toString());
					logParam.put("tranId", tranId);
					logParam.put("callBackReqBody", data.toString());
					logParam.put("callBackResBody", res.toString());
					logParam.put("errorCode", "RESPONSE_TIME_OUT");
					logParam.put("errorMsg", "응답시간(1.8초) 초과");
					logParam.put("regDate", startTimestamp);
					logParam.put("updDate", endTimestamp);
					callBackDao.insertCallBackErrLog(logParam);

					res = new JSONObject();
					res.put("result_code", -9999);
					res.put("error_msg", "RESPONSE_TIME_OUT");

					return res;
				}

				if (resultCode != 0 && resultCode != 98) {
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
					logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
					logParam.put("vendorIdx", data.get("vendorIdx"));
					logParam.put("statusCode", resultCode);
					logParam.put("callBackType", data.get("tranType").toString());
					logParam.put("tranId", tranId);
					logParam.put("callBackReqBody", data.toString());
					logParam.put("callBackResBody", res.toString());
					logParam.put("errorCode", "RESULT_CODE_ERR");
					logParam.put("errorMsg", res.toString());
					logParam.put("regDate", startTimestamp);
					logParam.put("updDate", endTimestamp);
					callBackDao.insertCallBackErrLog(logParam);

					// 에러로그넣기
					log.info(LOG_PREFIX + "changeBalance param : {}", data.toString());
					log.info(LOG_PREFIX + "changeBalance url : {}", baseCbUrl + "/changebalance");
					log.info(LOG_PREFIX + "changeBalance code : {}", statusCode);
					log.info(LOG_PREFIX + "changeBalance body: {}", responseBody);
				}
			} else {
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
				logParam.put("vendorIdx", data.get("vendorIdx"));
				logParam.put("statusCode", statusCode);
				logParam.put("callBackType", data.get("tranType").toString());
				logParam.put("tranId", tranId);
				logParam.put("callBackReqBody", data.toString());
				logParam.put("callBackResBody", StringUtils.truncateBodyForDb(responseBody, 1000));
				logParam.put("errorCode", "HTTP_STATUS_CODE_ERR");
				logParam.put("errorMsg", statusCode + " Error");
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", endTimestamp);
				callBackDao.insertCallBackErrLog(logParam);

				res = new JSONObject();
				res.put("result_code", -9999);
				res.put("error_msg", "HTTP_STATUS_CODE_ERR");

				return res;
			}

		} catch (WebClientRequestException e) {
			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산
			String errCode = "";
			String errMsg = "";

			Throwable cause = e.getCause();
			if (hasCause(cause, io.netty.channel.ConnectTimeoutException.class)
					|| hasCause(cause, java.net.ConnectException.class)) {
				log.error(LOG_PREFIX + "ConnectException e: CONNECT_TIMEOUT (3000ms)");
				log.error(LOG_PREFIX + "ConnectException e: {}", e.toString());
				errCode = "CONNECT_TIMEOUT";
				errMsg = "ConnectException e: CONNECT_TIMEOUT (3000ms)";
			} else if (hasCause(cause, io.netty.handler.timeout.ReadTimeoutException.class)
					|| hasCause(cause, java.net.SocketTimeoutException.class)) {
				log.error(LOG_PREFIX + "SocketTimeoutException e: READ_TIMEOUT (5000ms)");
				log.error(LOG_PREFIX + "SocketTimeoutException e: {}", e.toString());
				errCode = "READ_TIMEOUT";
				errMsg = "SocketTimeoutException e: READ_TIMEOUT (5000ms)";
			} else {
				log.error(LOG_PREFIX + "WebClientRequestException e: 기타 네트워크 예외 발생 발생!!!");
				log.error(LOG_PREFIX + "WebClientRequestException e: {}", e.toString());
				errCode = "NETWORK_ERROR";
				errMsg = "WebClientRequestException e: 기타 네트워크 예외 발생 발생!!!";
			}

			HashMap logParam = new HashMap();
			logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
			logParam.put("vendorIdx", null);
			logParam.put("statusCode", null);
			try {
				logParam.put("callBackType", data.get("tranType").toString());
			} catch (Exception de) {
				logParam.put("callBackType", "changebalance");
			}
			logParam.put("tranId", tranId);
			logParam.put("callBackReqBody", data.toString());
			logParam.put("callBackResBody", baseCbUrl + "/changebalance" + " > 실패");
			logParam.put("errorCode", errCode);
			logParam.put("errorMsg", errMsg);
			logParam.put("regDate", startTimestamp);
			logParam.put("updDate", endTimestamp);
			callBackDao.insertCallBackErrLog(logParam);

			try {
				res.put("result_code", -9999);
				res.put("error_msg", errMsg);
			} catch (JSONException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} catch (Exception e) {
			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산

			log.error(LOG_PREFIX + "Exception e: {}", e.toString());
			e.printStackTrace();

			HashMap logParam = new HashMap();
			logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
			logParam.put("vendorIdx", null);
			logParam.put("statusCode", null);
			try {
				logParam.put("callBackType", data.get("tranType").toString());
			} catch (Exception de) {
				logParam.put("callBackType", "changebalance");
			}
			logParam.put("tranId", tranId);
			logParam.put("callBackReqBody", data.toString());
			logParam.put("callBackResBody", baseCbUrl + "/changebalance" + " > 실패");
			logParam.put("regDate", startTimestamp);
			logParam.put("updDate", endTimestamp);
			callBackDao.insertCallBackErrLog(logParam);

			try {
				res.put("result_code", -9999);
				res.put("error_msg", "GENERAL_ERROR");
			} catch (JSONException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		return res;
	}
	

	@Override
	public JSONObject changeBalanceSlot(String LOG_PREFIX, HashMap siteApiInfo, JSONObject data) {

		JSONObject res = new JSONObject();
		String siteId = siteApiInfo.get("siteId").toString();
		String memberId = siteApiInfo.get("memberId").toString();
		String tranId = "";
		final String baseCbUrl = siteApiInfo.get("siteCbUrl").toString().trim();

		try {
			tranId = data.getString("tranId");
			log.info(LOG_PREFIX + "data.has(\"isData\"): " + data.has("isData"));
			log.info(LOG_PREFIX + "data.has(\"betKey\"): " + data.has("betKey"));
			if (!data.has("isData")) {
				data.put("isData", "N");
			}
			if (!data.has("betKey")) {
				data.put("betKey", tranId);
			}
		} catch (Exception e) {
		}

		HttpHeaders header = new HttpHeaders();
		header.add("Content-Type", MediaType.APPLICATION_JSON_VALUE);
		header.add("Accept", MediaType.APPLICATION_JSON_VALUE);
		header.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
				+ " AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
		header.set("Connection", "close");
		// 요청시간
		long startTimestamp = System.currentTimeMillis();
		log.info(LOG_PREFIX + "Callback URL: " + baseCbUrl + "/changebalance/slot");
		log.info(LOG_PREFIX + "Body: " + data.toString());

		try {
			/*
			ResponseEntity<String> responseEntity = webClient.post()
															.uri(baseCbUrl + "/changebalance/slot")
															.headers(h -> h.addAll(header))
															.bodyValue(data.toString())
															.retrieve().toEntity(String.class)
															.block();
			*/
			ResponseEntity<String> responseEntity = webClient.post().uri(baseCbUrl + "/changebalance/slot")
					.headers(h -> h.addAll(header)).bodyValue(data.toString())
					.exchangeToMono(resp -> resp.toEntity(String.class)).block();

			int statusCode = responseEntity.getStatusCode().value();
			String responseBody = responseEntity.getBody(); // 정상적으로 바디 읽기 가능

			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산

			int resultCode = 0;

			if (responseBody == null || responseBody.isEmpty()) {
				log.error(LOG_PREFIX + "Received empty or null response body from WebClient.");
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
				logParam.put("vendorIdx", data.get("vendorIdx"));
				logParam.put("statusCode", statusCode);
				try {
					logParam.put("callBackType", data.get("tranType").toString());
				} catch (Exception de) {
					logParam.put("callBackType", "changeBalanceSlot");
				}
				logParam.put("tranId", tranId);
				logParam.put("callBackReqBody", data.toString());
				logParam.put("callBackResBody", "Empty or null response body");
				logParam.put("errorCode", "EMPTY_RESPONSE");
				logParam.put("errorMsg", "WebClient returned empty or null body for /changebalance/slot");
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", System.currentTimeMillis());
				callBackDao.insertCallBackErrLog(logParam);

				res = new JSONObject();
				res.put("result_code", -9999);
				res.put("error_msg", "EMPTY_RESPONSE");

				return res;
			} else {
				res = new JSONObject(responseBody);
				if (res.has("result_code")) {
					resultCode = res.getInt("result_code");
				} else {
					resultCode = res.getInt("resultCode");
				}
			}

			if (statusCode == 200) {
				if (diffTime < -1.8) {
					log.error(LOG_PREFIX + "응답시간(1.8초) 초과");
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
					logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
					logParam.put("vendorIdx", data.get("vendorIdx"));
					logParam.put("statusCode", resultCode);
					logParam.put("callBackType", data.get("tranType").toString());
					logParam.put("tranId", tranId);
					logParam.put("callBackReqBody", data.toString());
					logParam.put("callBackResBody", res.toString());
					logParam.put("errorCode", "RESPONSE_TIME_OUT");
					logParam.put("errorMsg", "응답시간(1.8초) 초과");
					logParam.put("regDate", startTimestamp);
					logParam.put("updDate", endTimestamp);
					callBackDao.insertCallBackErrLog(logParam);

					res = new JSONObject();
					res.put("result_code", -9999);
					res.put("error_msg", "RESPONSE_TIME_OUT");

					return res;
				}

				if (resultCode != 0 && resultCode != 98) {
					HashMap logParam = new HashMap();
					logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
					logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
					logParam.put("vendorIdx", data.get("vendorIdx"));
					logParam.put("statusCode", resultCode);
					logParam.put("callBackType", data.get("tranType").toString());
					logParam.put("tranId", tranId);
					logParam.put("callBackReqBody", data.toString());
					logParam.put("callBackResBody", res.toString());
					logParam.put("errorCode", "RESULT_CODE_ERR");
					logParam.put("errorMsg", res.toString());
					logParam.put("regDate", startTimestamp);
					logParam.put("updDate", endTimestamp);
					callBackDao.insertCallBackErrLog(logParam);

					// 에러로그넣기
					log.info(LOG_PREFIX + "changeBalanceSlot param : {}", data.toString());
					log.info(LOG_PREFIX + "changeBalanceSlot url : {}", baseCbUrl + "/changebalance/slot");
					log.info(LOG_PREFIX + "changeBalanceSlot code : {}", statusCode);
					log.info(LOG_PREFIX + "changeBalanceSlot body: {}", responseBody);
				}
			} else {
				HashMap logParam = new HashMap();
				logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
				logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
				logParam.put("vendorIdx", data.get("vendorIdx"));
				logParam.put("statusCode", statusCode);
				logParam.put("callBackType", data.get("tranType").toString());
				logParam.put("tranId", tranId);
				logParam.put("callBackReqBody", data.toString());
				logParam.put("callBackResBody", StringUtils.truncateBodyForDb(responseBody, 1000));
				logParam.put("errorCode", "HTTP_STATUS_CODE_ERR");
				logParam.put("errorMsg", statusCode + " Error");
				logParam.put("regDate", startTimestamp);
				logParam.put("updDate", endTimestamp);
				callBackDao.insertCallBackErrLog(logParam);

				res = new JSONObject();
				res.put("result_code", -9999);
				res.put("error_msg", "HTTP_STATUS_CODE_ERR");

				return res;
			}

		} catch (WebClientRequestException e) {
			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산
			String errCode = "";
			String errMsg = "";

			Throwable cause = e.getCause();
			if (hasCause(cause, io.netty.channel.ConnectTimeoutException.class)
					|| hasCause(cause, java.net.ConnectException.class)) {
				log.error(LOG_PREFIX + "ConnectException e: CONNECT_TIMEOUT (3000ms)");
				log.error(LOG_PREFIX + "ConnectException e: {}", e.toString());
				errCode = "CONNECT_TIMEOUT";
				errMsg = "ConnectException e: CONNECT_TIMEOUT (3000ms)";
			} else if (hasCause(cause, io.netty.handler.timeout.ReadTimeoutException.class)
					|| hasCause(cause, java.net.SocketTimeoutException.class)) {
				log.error(LOG_PREFIX + "SocketTimeoutException e: READ_TIMEOUT (5000ms)");
				log.error(LOG_PREFIX + "SocketTimeoutException e: {}", e.toString());
				errCode = "READ_TIMEOUT";
				errMsg = "SocketTimeoutException e: READ_TIMEOUT (5000ms)";
			} else {
				log.error(LOG_PREFIX + "WebClientRequestException e: 기타 네트워크 예외 발생 발생!!!");
				log.error(LOG_PREFIX + "WebClientRequestException e: {}", e.toString());
				errCode = "NETWORK_ERROR";
				errMsg = "WebClientRequestException e: 기타 네트워크 예외 발생 발생!!!";
			}

			HashMap logParam = new HashMap();
			logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
			logParam.put("vendorIdx", null);
			logParam.put("statusCode", null);
			try {
				logParam.put("callBackType", data.get("tranType").toString());
			} catch (Exception de) {
				logParam.put("callBackType", "changeBalanceSlot");
			}
			logParam.put("tranId", tranId);
			logParam.put("callBackReqBody", data.toString());
			logParam.put("callBackResBody", baseCbUrl + "/changebalance/slot" + " > 실패");
			logParam.put("errorCode", errCode);
			logParam.put("errorMsg", errMsg);
			logParam.put("regDate", startTimestamp);
			logParam.put("updDate", endTimestamp);
			callBackDao.insertCallBackErrLog(logParam);

			try {
				res.put("result_code", -9999);
				res.put("error_msg", errMsg);
			} catch (JSONException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} catch (Exception e) {
			long endTimestamp = System.currentTimeMillis();
			double diffTime = (startTimestamp - endTimestamp) / 1000.0; // 두 시간에 차 계산

			log.error(LOG_PREFIX + "Exception e: {}", e.toString());
			e.printStackTrace();

			HashMap logParam = new HashMap();
			logParam.put("siteIdx", siteApiInfo.get("siteIdx"));
			logParam.put("memberIdx", siteApiInfo.get("memberIdx"));
			logParam.put("vendorIdx", null);
			logParam.put("statusCode", null);
			try {
				logParam.put("callBackType", data.get("tranType").toString());
			} catch (Exception de) {
				logParam.put("callBackType", "changeBalanceSlot");
			}
			logParam.put("tranId", tranId);
			logParam.put("callBackReqBody", data.toString());
			logParam.put("callBackResBody", baseCbUrl + "/changebalance/slot" + " > 실패");
			logParam.put("regDate", startTimestamp);
			logParam.put("updDate", endTimestamp);
			callBackDao.insertCallBackErrLog(logParam);

			try {
				res.put("result_code", -9999);
				res.put("error_msg", "GENERAL_ERROR");
			} catch (JSONException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		return res;
	}

	@Override
	public void insertCallBackErrLog(HashMap logParam) {
		// TODO Auto-generated method stub
		callBackDao.insertCallBackErrLog(logParam);
	}

	private boolean hasCause(Throwable e, Class<? extends Throwable> clazz) {
		Throwable cause = e;
		while (cause != null) {
			if (clazz.isInstance(cause)) {
				return true;
			}
			cause = cause.getCause();
		}
		return false;
	}

}