package com.bb.service;

import java.net.SocketTimeoutException;
import java.util.ArrayList;
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.JSONException;
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.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.reactive.function.client.WebClient;

import com.bb.dao.SiteDao;
import com.bb.model.Game;
import com.bb.model.GsoftApiInfo;
import com.bb.model.VendorChangeBalanceLogVo;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class GsoftServiceImpl implements GsoftService {

	@Autowired
	private SiteDao siteDao;
	
	@Autowired
	WebClient webClient;
	
	
	@Override
	public JSONObject getBalanceUser(GsoftApiInfo apiInfo) {
		JSONObject userBalanceJson = null;
		
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			headers.set("Authorization", apiInfo.getApiAuthKey());
			
			JSONObject params = new JSONObject();
			params.put("userid", apiInfo.getUserId());
			params.put("amount", 0);
			params.put("type", "0");
			
			String balanceUrl = apiInfo.getApiBaseUrl() + "/csapi/amount";
			log.info("## GSOFT API ## balanceUrl: " + balanceUrl);
			log.info("## GSOFT API ## balanceHeaders: " + headers.toString());
			log.info("## GSOFT API ## balanceParams: " + params.toString());
			
			ResponseEntity<String> res = webClient.post()
					.uri(balanceUrl)
					.headers(h -> h.addAll(headers))
					.bodyValue(params.toString())
					.retrieve()
					.toEntity(String.class)
					.block();

			log.info("## GSOFT API ## Request \"/csapi/amount\" res : " + res.getBody());
			userBalanceJson = new JSONObject(res.getBody());
			
		} 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());
            }
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(str);
		} catch (Exception e) {
			log.error(e.toString());
			e.printStackTrace();
        }
		
		return userBalanceJson;
	}

	@Override
	public JSONObject depositUser(GsoftApiInfo apiInfo, int amount) {
		JSONObject depositJson = null;
		
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			headers.set("Authorization", apiInfo.getApiAuthKey());
			
			JSONObject params = new JSONObject();
			params.put("userid", apiInfo.getUserId());
			params.put("amount", amount);
			params.put("type", "1");
			
			String depositUrl = apiInfo.getApiBaseUrl() + "/csapi/amount";
			log.info("## GSOFT API ## depositUrl: " + depositUrl);
			log.info("## GSOFT API ## depositHeaders: " + headers.toString());
			log.info("## GSOFT API ## depositParams: " + params.toString());
			
			log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "depositParams::"+params.toString());
			
			ResponseEntity<String> res = webClient.post()
					.uri(depositUrl)
					.headers(h -> h.addAll(headers))
					.bodyValue(params.toString())
					.retrieve()
					.toEntity(String.class)
					.block();
			log.info("## GSOFT API ## Request \"/csapi/amount\" res : " + res.getBody());
			depositJson = new JSONObject(res.getBody());
			
			if(depositJson.getInt("result") == 1) {
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("gsoft")
						.vendorApiId(apiInfo.getClientId())
						.reqType("deposit")
						.amount(amount)
						.reqAt(apiInfo.getReqAt())
						.reqStatus("SUCC")
						.reqMsg(depositJson.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		} else {
    			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("gsoft")
						.vendorApiId(apiInfo.getClientId())
						.reqType("deposit")
						.amount(amount)
						.reqAt(apiInfo.getReqAt())
						.reqStatus("FAIL")
						.reqMsg(depositJson.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[InterruptedException]"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("gsoft")
					.vendorApiId(apiInfo.getClientId())
					.reqType("deposit")
					.amount(amount)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
            
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[HttpClientErrorException]"+str);
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("gsoft")
					.vendorApiId(apiInfo.getClientId())
					.reqType("deposit")
					.amount(amount)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg(str)
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			
		} catch (Exception e) {
			log.error("#-depositProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[Exception]"+e.toString());
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("gsoft")
					.vendorApiId(apiInfo.getClientId())
					.reqType("deposit")
					.amount(amount)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("Exception e")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
        }
		
		return depositJson;
	}

	@Override
	public JSONObject withdrawUser(GsoftApiInfo apiInfo) {
		JSONObject withdrawJson = null;
		
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			headers.set("Authorization", apiInfo.getApiAuthKey());
			
			JSONObject params = new JSONObject();
			params.put("userid", apiInfo.getUserId());
			params.put("amount", 0);
			params.put("type", "3");
			
			String withdrawUrl = apiInfo.getApiBaseUrl() + "/csapi/amount";
			log.info("## GSOFT API ## withdrawUrl: " + withdrawUrl);
			log.info("## GSOFT API ## withdrawHeaders: " + headers.toString());
			log.info("## GSOFT API ## withdrawParams: " + params.toString());
			
			ResponseEntity<String> res = webClient.post()
					.uri(withdrawUrl)
					.headers(h -> h.addAll(headers))
					.bodyValue(params.toString())
					.retrieve()
					.toEntity(String.class)
					.block();
			log.info("## GSOFT API ## Request \"/csapi/amount\" res : " + res.getBody());
			withdrawJson = new JSONObject(res.getBody());
			
			if(withdrawJson.getInt("result") == 1) {
				VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("gsoft")
						.vendorApiId(apiInfo.getClientId())
						.reqType("withdrawAll")
						.amount(0)
						.reqAt(apiInfo.getReqAt())
						.reqStatus("SUCC")
						.reqMsg(withdrawJson.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		} else {
    			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
						.siteIdx(apiInfo.getSiteIdx())
						.memberIdx(apiInfo.getMemberIdx())
						.vendor("gsoft")
						.vendorApiId(apiInfo.getClientId())
						.reqType("withdrawAll")
						.amount(0)
						.reqAt(apiInfo.getReqAt())
						.reqStatus("FAIL")
						.reqMsg(withdrawJson.getString("msg"))
						.build();
				siteDao.insertVendorChangeBalanceLog(logVo);
    		}
			
		} catch (ResourceAccessException rae) {
            if(rae.getCause() instanceof ConnectTimeoutException) {
            	log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[ConnectTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof SocketTimeoutException) {
            	log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[SocketTimeoutException]"+rae.getMessage());
            }
        
            if(rae.getCause() instanceof InterruptedException) {
            	log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[InterruptedException]"+rae.getMessage());
            }
            
            VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("gsoft")
					.vendorApiId(apiInfo.getClientId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("TimeoutException")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
            
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[HttpClientErrorException]"+str);
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("gsoft")
					.vendorApiId(apiInfo.getClientId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg(str)
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
			
		} catch (Exception e) {
			log.error("#-withdrawProc::"+apiInfo.getSiteIdx()+"::"+apiInfo.getMemberIdx()+"::"+apiInfo.getReqAt()+"::gsoft::"+ "[Exception]"+e.toString());
			e.printStackTrace();
			
			VendorChangeBalanceLogVo logVo = VendorChangeBalanceLogVo.builder()
					.siteIdx(apiInfo.getSiteIdx())
					.memberIdx(apiInfo.getMemberIdx())
					.vendor("gsoft")
					.vendorApiId(apiInfo.getClientId())
					.reqType("withdrawAll")
					.amount(0)
					.reqAt(apiInfo.getReqAt())
					.reqStatus("FAIL")
					.reqMsg("Exception e")
					.build();
			siteDao.insertVendorChangeBalanceLog(logVo);
        }
		
		return withdrawJson;
	}

	@Override
	public List<Game> gameList(GsoftApiInfo apiInfo) {
		
		List<Game> gameList = null;
		
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			headers.set("Authorization", apiInfo.getApiAuthKey());
			
			JSONObject params = new JSONObject();
			params.put("type", 2);
			params.put("gameid", apiInfo.getGameId());
			params.put("code", apiInfo.getCode());
			
			String slotUrl = apiInfo.getApiBaseUrl() + "/csapi/Provider";
			log.info("## GSOFT API ## slotUrl: " + slotUrl);
			log.info("## GSOFT API ## slotHeaders: " + headers.toString());
			log.info("## GSOFT API ## slotParams: " + params.toString());
			
			ResponseEntity<String> res = webClient.post()
					.uri(slotUrl)
					.headers(h -> h.addAll(headers))
					.bodyValue(params.toString())
					.retrieve()
					.toEntity(String.class)
					.block();
//			log.info("## GSOFT API ## Request \"/csapi/amount\" res : " + res.getBody());
			JSONObject slotJson = new JSONObject(res.getBody());
			
			if(slotJson.getInt("result") == 1) {
				log.info("## GSOFT API ## Game List msg: " + slotJson.getString("msg"));
				JSONArray games = slotJson.getJSONArray("data");
				int length = games.length();
				gameList = new ArrayList<>();
				
				for(int i=0; i<length; i++) {
					Game game = new Game();
					JSONObject objGame = games.getJSONObject(i);
					game.setGameIdx(i);
					game.setGameKey(objGame.getString("subcode"));
					game.setGameName(objGame.getString("name_kor"));
					game.setGameNameEn(objGame.getString("name_eng"));
					game.setGameImg(objGame.getString("img"));
					gameList.add(game);
				}
				log.info("## GSOFT API ## Game List length: " + length);
				
			} else {
				log.error("## GSOFT API ## Game List Error: " + slotJson.getString("msg"));
			}
			
		} 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());
            }
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(str);
		} catch (Exception e) {
			log.error(e.toString());
			e.printStackTrace();
        }
		
		return gameList;
	}

	@Override
	public String getComanyBalance(HashMap vendor) {
	JSONObject userBalanceJson = null;
	String balance ="0";
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			headers.set("Authorization", vendor.get("key").toString());
			
					
			String balanceUrl = "https://api.vblive.net/csapi/AGInfo";

			ResponseEntity<String> res = webClient.post()
					.uri(balanceUrl)
					.headers(h -> h.addAll(headers)) // 기존의 HttpHeaders 객체 적용
					.retrieve()
					.toEntity(String.class)          // Mono<ResponseEntity<String>>를 반환
					.block();

			log.info("## GSOFT API ## Request \"/csapi/amount\" res : " + res.getBody());
			userBalanceJson = new JSONObject(res.getBody());
			balance =  userBalanceJson.get("balance2").toString();
			
		} 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());
            }
		} catch(HttpClientErrorException hee) {
			String str = hee.getResponseBodyAsString();
			log.error(str);
		} catch (Exception e) {
			log.error(e.toString());
			e.printStackTrace();
        }
		
		return balance;
	}

}
