package com.bb.service;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;

import org.apache.http.conn.ConnectTimeoutException;
import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponentsBuilder;

import com.bb.dao.SiteDao;
import com.bb.dao.TplusDao;
import com.bb.model.Game;
import com.bb.model.TplusApiInfo;
import com.bb.model.VendorChangeBalanceLogVo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class TplusServiceImpl implements TplusService {
	
	@Autowired
	private TplusDao tplusDao;
	
	@Autowired
	private SiteDao siteDao;
	
	@Autowired
	WebClient webClient;
	

	@Override
	public Long getBalanceUser(String LOG_PREFIX, TplusApiInfo apiInfo) {
		JSONObject resJson = null;
		Long balance = null;
		LOG_PREFIX = LOG_PREFIX+"tplus::getBalanceUser::";
		
		try {
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+apiInfo.getApiAuthKey());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/Balance");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getApiUsername());
			
			HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(params, header);
			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue(params)
						.retrieve()
						.toEntity(String.class)
						.block();
				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info(LOG_PREFIX+ "code: " + resJson.getInt("code"));
				log.info(LOG_PREFIX+ "message: " + resJson.getString("message"));
				balance = resJson.getLong("total_balance");
			} else {
				balance = 0L;
				log.error(LOG_PREFIX+ "code: " + resJson.getInt("code"));
				log.error(LOG_PREFIX+ "message: " + resJson.getString("message"));
			}
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
            balance = 0L;
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(LOG_PREFIX+ "HttpClientErrorException::"+str);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.toString());
			e.printStackTrace();
        }
		
		return balance;
	}

	@Override
	public String depositUser(String LOG_PREFIX, TplusApiInfo apiInfo, Long amount) {
		JSONObject resJson = null;
		String resultCode = "0";

		
		try {
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+apiInfo.getApiAuthKey());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/Deposit");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getApiUsername());
			params.add("amount", amount.longValue());
			params.add("unique_key", String.valueOf(System.currentTimeMillis()));
			HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(params, header);
			log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "depositParams::"+params.toString());

			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue(params)
						.retrieve()
						.toEntity(String.class)
						.block();
				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info("## Tplus API ## depositUser() code: " + resJson.getInt("code"));
				log.info("## Tplus API ## depositUser() message: " + resJson.getString("message"));
				
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("tplus")
						.vendorApiId(apiInfo.getClientId())
						.reqType("deposit")
						.amount(amount.intValue())
						.reqAt(apiInfo.getReqAt())
						.reqStatus("SUCC")
						.reqMsg(resJson.getString("message"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
				
			} else {
				resultCode = Integer.toString(resJson.getInt("code"));
				log.info("## Tplus API ## depositUser() code: " + resJson.getInt("code"));
				log.info("## Tplus API ## depositUser() message: " + resJson.getString("message"));
				
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("tplus")
						.vendorApiId(apiInfo.getClientId())
						.reqType("deposit")
						.amount(amount.intValue())
						.reqAt(apiInfo.getReqAt())
						.reqStatus("FAIL")
						.reqMsg(resJson.getString("message"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
			}
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[InterruptedException]"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("tplus")
					.vendorApiId(apiInfo.getClientId())
					.reqType("deposit")
					.amount(amount.intValue())
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			resultCode = "-1";
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[HttpClientErrorException]"+str);
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("tplus")
					.vendorApiId(apiInfo.getClientId())
					.reqType("deposit")
					.amount(amount.intValue())
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg(str)
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			resultCode = "-1";
		} catch (Exception e) {
			log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[Exception]"+e.toString());
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("tplus")
					.vendorApiId(apiInfo.getClientId())
					.reqType("deposit")
					.amount(amount.intValue())
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("Exception e")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			e.printStackTrace();
			resultCode = "-1";
        }
		
		return resultCode;
	}

	@Override
	public String withdrawUser(String LOG_PREFIX, TplusApiInfo apiInfo) {
		JSONObject resJson = null;
		String resultCode = "0";

		
		try {
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+apiInfo.getApiAuthKey());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/Withdraw");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("username", apiInfo.getApiUsername());
			params.add("unique_key", String.valueOf(System.currentTimeMillis()));
			HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(params, header);
			
			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue(params)
						.retrieve()
						.toEntity(String.class)
						.block();
				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info("## Tplus API ## withdrawUser() code: " + resJson.getInt("code"));
				log.info("## Tplus API ## withdrawUser() message: " + resJson.getString("message"));
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("tplus")
						.vendorApiId(apiInfo.getClientId())
						.reqType("withdrawAll")
						.amount(0)
						.reqAt(apiInfo.getReqAt())
						.reqStatus("SUCC")
						.reqMsg(resJson.getString("message"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
			} else {
				resultCode = Integer.toString(resJson.getInt("code"));
				log.info("## Tplus API ## withdrawUser() code: " + resJson.getInt("code"));
				log.info("## Tplus API ## withdrawUser() message: " + resJson.getString("message"));
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("tplus")
						.vendorApiId(apiInfo.getClientId())
						.reqType("withdrawAll")
						.amount(0)
						.reqAt(apiInfo.getReqAt())
						.reqStatus("FAIL")
						.reqMsg(resJson.getString("resultMessage"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
			}
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[InterruptedException]"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("tplus")
					.vendorApiId(apiInfo.getClientId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			resultCode = "-1";
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[HttpClientErrorException]"+str);
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("tplus")
					.vendorApiId(apiInfo.getClientId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg(str)
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			resultCode = "-1";
		} catch (Exception e) {
			log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::tplus::"+ "[Exception]"+e.toString());
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("tplus")
					.vendorApiId(apiInfo.getClientId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("Exception e")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			e.printStackTrace();
			resultCode = "-1";
        }
		
		return resultCode;
	}

	@Override
	public List<Game> gameList(String LOG_PREFIX, TplusApiInfo apiInfo) {
		JSONObject resJson = null;
		List<Game> gameList = null;
		LOG_PREFIX = LOG_PREFIX+"tplus::gameList::";
		
		try {
			
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+apiInfo.getApiAuthKey());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/Games");
			MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
			params.add("thirdparty", apiInfo.getThirdparty());
			HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(params, header);
			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue(params)
						.retrieve()
						.toEntity(String.class)
						.block();

				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info(LOG_PREFIX+ "result: " + resJson.getString("message"));
				gameList = new ArrayList<>();
				JSONArray games = resJson.getJSONArray("data");
				int length = games.length();
				
				for(int i=0; i<length; i++) {
					Game game = new Game();
					JSONObject objGame = games.getJSONObject(i);
					game.setGameIdx(i);
					game.setGameKey(objGame.getString("uuid"));
					game.setGameName(objGame.getString("name_kr"));
					game.setGameNameEn(objGame.getString("name_en"));
					game.setGameImg(objGame.getString("image"));
					gameList.add(game);
				}
			} else {
				log.error(LOG_PREFIX+ "code: " + resJson.getInt("code"));
				log.error(LOG_PREFIX+ "message: " + resJson.getString("message"));
			}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(LOG_PREFIX+ "HttpClientErrorException::"+str);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.toString());
			e.printStackTrace();
        }
		
		return gameList;
	}

	@Override
	public String getGameLink(String LOG_PREFIX, TplusApiInfo apiInfo) {
		JSONObject resJson = null;
		String gameUrl = null;
		LOG_PREFIX = LOG_PREFIX+"tplus::getGameLink::";
		
		try {
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+apiInfo.getApiAuthKey());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/Link");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("thirdparty", apiInfo.getThirdparty());
			params.add("uuid", apiInfo.getUuid());
			params.add("username", apiInfo.getApiUsername());
			HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, header);
			
			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue(params)
						.retrieve()
						.toEntity(String.class)
						.block();
				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info(LOG_PREFIX+ "message: " + resJson.getString("message"));
				gameUrl = resJson.getString("url");
			} else {
				log.error(LOG_PREFIX+ "code: " + resJson.getInt("code"));
				log.error(LOG_PREFIX+ "message: " + resJson.getString("message"));
			}
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(LOG_PREFIX+ "HttpClientErrorException::"+str);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.toString());
			e.printStackTrace();
        }
		
		return gameUrl;
	}

	@Override
	public String getComanyBalance(HashMap vendor) {
		JSONObject resJson = null;
		String balance = "0";

		
		try {
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+vendor.get("key").toString());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://api.seven-gameapi.com/AgentBalance");
			
			
			HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(null, header);
			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue("")
						.retrieve()
						.toEntity(String.class)
						.block();
				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info("## Tplus API ## getBalanceUser() code: " + resJson.getInt("code"));
				log.info("## Tplus API ## getBalanceUser() message: " + resJson.getString("message"));
				balance = resJson.get("agent_balance").toString();
			} else {
				  balance = "0";
				log.info("## Tplus API ## getBalanceUser() code: " + resJson.getInt("code"));
				log.info("## Tplus API ## getBalanceUser() message: " + resJson.getString("message"));
			}
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error("[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error("[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error("[InterruptedException]"+rae.getMessage());
            }
            balance = "0";
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(str);
		} catch (Exception e) {
			log.error(e.toString());
			e.printStackTrace();
        }
		
		return balance;
	}

	@Override
	public String getDetails(String LOG_PREFIX, TplusApiInfo apiInfo) {
		JSONObject resJson = null;
		String detailUrl = null;
		LOG_PREFIX = LOG_PREFIX+"tplus::getDetails::";
		
		try {
			HttpHeaders header = new HttpHeaders(); 
			header.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
			header.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
			header.set("Authorization", "Bearer "+apiInfo.getApiAuthKey());
			
			UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(apiInfo.getApiBaseUrl() + "/Details");
			MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
			params.add("pair_transaction_key", apiInfo.getPairTransactionKey());
			HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<>(params, header);
			
			ResponseEntity<String> response = null;
			try {
				response = webClient.post()
						.uri(builder.toUriString())
						.headers(h -> h.addAll(header))
						.bodyValue(params)
						.retrieve()
						.toEntity(String.class)
						.block();
				resJson = new JSONObject(response != null ? response.getBody() : "{}");
			} catch (Exception ex) {
				Throwable cause = ex.getCause();
				if (cause instanceof ConnectTimeoutException || cause instanceof java.net.SocketTimeoutException || cause instanceof InterruptedException) {
					throw new ResourceAccessException(ex.getMessage(), new java.io.IOException(cause));
				}
				throw ex;
			}
			if(resJson.getInt("code") == 0) {
				log.info(LOG_PREFIX+ "message: " + resJson.getString("message"));
				detailUrl = resJson.getString("url");
				log.info(LOG_PREFIX+ "detailUrl: " + detailUrl);
			} else {
				log.error(LOG_PREFIX+ "code: " + resJson.getInt("code"));
				log.error(LOG_PREFIX+ "message: " + resJson.getString("message"));
			}
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error(LOG_PREFIX+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error(LOG_PREFIX+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error(LOG_PREFIX+ "[InterruptedException]"+rae.getMessage());
            }
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(LOG_PREFIX+ "HttpClientErrorException::"+str);
		} catch (Exception e) {
			log.error(LOG_PREFIX+ "Exception::"+e.toString());
			e.printStackTrace();
        }
		
		return detailUrl;
	}

}
