package com.bb.admin.controller;

import java.util.HashMap;
import java.util.List;

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.bb.model.Credit;
import com.bb.model.CreditPoint;
import com.bb.model.OTPInfo;
import com.bb.model.PageFormVO;
import com.bb.model.Site;
import com.bb.model.SiteSearch;
import com.bb.service.CreditService;
import com.bb.service.SiteService;
import com.bb.util.PagingUtil;
import com.bb.util.TOTPTokenGenerator;

import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;

@Slf4j
@Controller
@RequestMapping(value = "/cash")
@PreAuthorize("hasRole('ADMIN')")
public class CreditController {

	@Autowired
	SiteService siteService;

	@Autowired
	CreditService creditService;

	@GetMapping("/charge")
	public String charge(HttpServletRequest request, ModelMap model, @ModelAttribute("searchVO") SiteSearch search)
			throws Exception {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();
		model.put("loginSite", loginSite);
		long siteCredit = siteService.getSiteCredit(loginSite.getSiteId());
		long underSiteCredit = siteService.getUnderSiteCredit(loginSite.getSiteId());
		log.info("underSiteCredit" + underSiteCredit);
		model.put("siteCredit", siteCredit);
		model.put("underSiteCredit", underSiteCredit);
		long sitePoint = siteService.getSitePoint(loginSite.getSiteId());
		model.put("sitePoint", sitePoint);
		HashMap creditWait = siteService.getCreditWait(loginSite.getSiteIdx());
		model.put("creditWait", creditWait);
		long insureAmt = siteService.getInsureAmt(loginSite.getSiteId());
		long insurePointAmt = siteService.getInsurePointAmt(loginSite.getSiteId());
		model.put("insureAmt", insureAmt);
		model.put("insurePointAmt", insurePointAmt);

		PageFormVO pageVo = new PageFormVO();
		search.setSiteId(loginSite.getSiteId());
		search.setSiteIdx(loginSite.getSiteIdx());
		search.setCreditType("CI");

		int totalCount = creditService.getCreditListCnt(search);
		if (totalCount != 0) {
			PageFormVO commonForm = new PageFormVO();
			commonForm.setFunction_name("goPage");
			commonForm.setPage(search.getPage());
			commonForm.setCount_per_page(20);
			if (search.getCount_per_list() == 0) {
				commonForm.setCount_per_list(10);
			} else {
				commonForm.setCount_per_list(search.getCount_per_list());
			}
			commonForm.setTatal_list_count(totalCount);
			pageVo = PagingUtil.setPageUtil(commonForm);
			search.setLimit(pageVo.getLimit());
			search.setOffset(pageVo.getOffset());
			search.setTatal_list_count(totalCount);

			model.put("pageInfo", pageVo.getPagination());
		}

		HashMap sum = creditService.getCreditSumToday(search);
		model.put("sum", sum);

		List<HashMap> list = creditService.getCreditList(search);
		log.info("list" + list.size());
		model.put("list", list);

		return "admin/charge";
	}

	@GetMapping("/chargeWait")
	public String chargeWait(HttpServletRequest request, ModelMap model, @ModelAttribute("searchVO") SiteSearch search)
			throws Exception {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();
		model.put("loginSite", loginSite);
		long siteCredit = siteService.getSiteCredit(loginSite.getSiteId());
		long underSiteCredit = siteService.getUnderSiteCredit(loginSite.getSiteId());
		log.info("underSiteCredit" + underSiteCredit);
		model.put("siteCredit", siteCredit);
		model.put("underSiteCredit", underSiteCredit);
		long sitePoint = siteService.getSitePoint(loginSite.getSiteId());
		model.put("sitePoint", sitePoint);
		HashMap creditWait = siteService.getCreditWait(loginSite.getSiteIdx());
		model.put("creditWait", creditWait);
		long insureAmt = siteService.getInsureAmt(loginSite.getSiteId());
		long insurePointAmt = siteService.getInsurePointAmt(loginSite.getSiteId());
		model.put("insureAmt", insureAmt);
		model.put("insurePointAmt", insurePointAmt);

		PageFormVO pageVo = new PageFormVO();
		search.setSiteId(loginSite.getSiteId());
		search.setSiteIdx(loginSite.getSiteIdx());
		search.setCreditType("CI");
		search.setCreditStatus(request.getParameter("creditStatus"));
		log.info(search.getCreditStatus());

		int totalCount = creditService.getCreditListCnt(search);
		if (totalCount != 0) {
			PageFormVO commonForm = new PageFormVO();
			commonForm.setFunction_name("goPage");
			commonForm.setPage(search.getPage());
			commonForm.setCount_per_page(20);
			if (search.getCount_per_list() == 0) {
				commonForm.setCount_per_list(10);
			} else {
				commonForm.setCount_per_list(search.getCount_per_list());
			}
			commonForm.setTatal_list_count(totalCount);
			pageVo = PagingUtil.setPageUtil(commonForm);
			search.setLimit(pageVo.getLimit());
			search.setOffset(pageVo.getOffset());
			search.setTatal_list_count(totalCount);

			model.put("pageInfo", pageVo.getPagination());
		}

		log.info(search.getCreditStatus());
		List<HashMap> list = creditService.getCreditList(search);
		log.info("" + list.size());
		model.put("list", list);

		return "admin/apply";
	}

	@GetMapping("/exchange")
	public String exchange(HttpServletRequest request, ModelMap model, @ModelAttribute("searchVO") SiteSearch search)
			throws Exception {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();
		model.put("loginSite", loginSite);
		long siteCredit = siteService.getSiteCredit(loginSite.getSiteId());
		long underSiteCredit = siteService.getUnderSiteCredit(loginSite.getSiteId());
		log.info("underSiteCredit" + underSiteCredit);
		model.put("siteCredit", siteCredit);
		model.put("underSiteCredit", underSiteCredit);
		long sitePoint = siteService.getSitePoint(loginSite.getSiteId());
		model.put("sitePoint", sitePoint);
		HashMap creditWait = siteService.getCreditWait(loginSite.getSiteIdx());
		model.put("creditWait", creditWait);
		long insureAmt = siteService.getInsureAmt(loginSite.getSiteId());
		long insurePointAmt = siteService.getInsurePointAmt(loginSite.getSiteId());
		model.put("insureAmt", insureAmt);
		model.put("insurePointAmt", insurePointAmt);

		PageFormVO pageVo = new PageFormVO();
		search.setSiteId(loginSite.getSiteId());
		search.setSiteIdx(loginSite.getSiteIdx());
		search.setCreditType("CO");
		search.setCreditStatus(request.getParameter("creditStatus"));
		log.info(search.getCreditStatus());

		int totalCount = creditService.getCreditListCnt(search);
		if (totalCount != 0) {
			PageFormVO commonForm = new PageFormVO();
			commonForm.setFunction_name("goPage");
			commonForm.setPage(search.getPage());
			commonForm.setCount_per_page(20);
			if (search.getCount_per_list() == 0) {
				commonForm.setCount_per_list(10);
			} else {
				commonForm.setCount_per_list(search.getCount_per_list());
			}
			commonForm.setTatal_list_count(totalCount);
			pageVo = PagingUtil.setPageUtil(commonForm);
			search.setLimit(pageVo.getLimit());
			search.setOffset(pageVo.getOffset());
			search.setTatal_list_count(totalCount);

			model.put("pageInfo", pageVo.getPagination());
		}

		List<HashMap> list = creditService.getCreditList(search);
		model.put("list", list);

		return "admin/exchange";
	}

	@GetMapping("/exchangeWait")
	public String exchangeWait(HttpServletRequest request, ModelMap model,
			@ModelAttribute("searchVO") SiteSearch search) throws Exception {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();
		model.put("loginSite", loginSite);
		long siteCredit = siteService.getSiteCredit(loginSite.getSiteId());
		long underSiteCredit = siteService.getUnderSiteCredit(loginSite.getSiteId());
		log.info("underSiteCredit" + underSiteCredit);
		model.put("siteCredit", siteCredit);
		model.put("underSiteCredit", underSiteCredit);
		long sitePoint = siteService.getSitePoint(loginSite.getSiteId());
		model.put("sitePoint", sitePoint);
		HashMap creditWait = siteService.getCreditWait(loginSite.getSiteIdx());
		model.put("creditWait", creditWait);
		long insureAmt = siteService.getInsureAmt(loginSite.getSiteId());
		long insurePointAmt = siteService.getInsurePointAmt(loginSite.getSiteId());
		model.put("insureAmt", insureAmt);
		model.put("insurePointAmt", insurePointAmt);

		PageFormVO pageVo = new PageFormVO();
		search.setSiteId(loginSite.getSiteId());
		search.setSiteIdx(loginSite.getSiteIdx());
		search.setCreditType("CO");

		int totalCount = creditService.getCreditListCnt(search);
		if (totalCount != 0) {
			PageFormVO commonForm = new PageFormVO();
			commonForm.setFunction_name("goPage");
			commonForm.setPage(search.getPage());
			commonForm.setCount_per_page(20);
			if (search.getCount_per_list() == 0) {
				commonForm.setCount_per_list(10);
			} else {
				commonForm.setCount_per_list(search.getCount_per_list());
			}
			commonForm.setTatal_list_count(totalCount);
			pageVo = PagingUtil.setPageUtil(commonForm);
			search.setLimit(pageVo.getLimit());
			search.setOffset(pageVo.getOffset());
			search.setTatal_list_count(totalCount);

			model.put("pageInfo", pageVo.getPagination());
		}

		List<HashMap> list = creditService.getCreditList(search);
		model.put("list", list);

		return "admin/exchangeapply";
	}

	@RequestMapping("/addProc")
	public @ResponseBody JSONObject addProc(HttpServletRequest request, ModelMap model, Credit credit)
			throws Exception {

		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();

		long siteCredit = siteService.getSiteCredit(loginSite.getSiteId());

		JSONObject obj = new JSONObject();
		// enum('AI','AO','CI','CO','DP','CD','SDP','SCD')
		// inout (받는사람 기준으로 인인지 아웃인지)
		// status 바로적립 1, 승인대기 0
		// siteId 타겟사이트 아이디
		final String LOG_PREFIX = "#-super::CREDIT_DEPOSIT:::";
		log.info(LOG_PREFIX + "Credit::" + credit.toString());

		if ("AI".equals(credit.getCreditType()) || "AO".equals(credit.getCreditType())) {
			OTPInfo otpManager = siteService.getOtpInfoByManger(loginSite.getSiteIdx());
			if (otpManager == null || otpManager.getAccount().equals("")) {
				log.error(LOG_PREFIX + "OTP정보가 없습니다.");
				obj.put("RES", "FAIL");
				obj.put("MSG", "OTP정보가 없습니다.");
				return obj;
			} else {
				log.info(LOG_PREFIX + "OTP Info::" + otpManager.toString());
				String secret = otpManager.getSecretKey();
				if (credit.getOtp() == null || "".equals(credit.getOtp())) {
					log.error(LOG_PREFIX + "OTP 번호를 입력하세요.");
					obj.put("RES", "FAIL");
					obj.put("MSG", "OTP 번호를 입력하세요.");
					return obj;
				}

				boolean chkOtp = TOTPTokenGenerator.otpVerify(secret, Integer.parseInt(credit.getOtp()));
				if (!chkOtp) {
					log.error(LOG_PREFIX + "OTP 번호가 일치하지 않습니다.");
					obj.put("RES", "FAIL");
					obj.put("MSG", "OTP 번호가 일치하지 않습니다.");
					return obj;
				}
			}

		    SiteSearch search = new SiteSearch();
	      	search.setSiteId(credit.getTargetSiteId());
			search.setSiteIdx(credit.getTargetSiteIdx());
	      	Site targetSite = siteService.getSiteDetail(search);
	      	credit.setSiteLevel(targetSite.getSiteLevel());
		}

		if ("AI".equals(credit.getCreditType())) { // 관리 직접 지금

			if (siteCredit < credit.getCreditAmt()) {
				obj.put("RES", "FAIL");
				obj.put("MSG", "크레딧이 모자릅니다.");
				return obj;
			}

			credit.setInOut("IN");
			credit.setCreditStatus(1);
			credit.setSiteIdx(loginSite.getSiteIdx());
			credit.setSiteId(loginSite.getSiteId());

		} else if ("AO".equals(credit.getCreditType())) { // 관리자 직접환급

			long targetSiteCredit = siteService.getSiteCredit(credit.getTargetSiteId());

			if (targetSiteCredit < credit.getCreditAmt()) {
				obj.put("RES", "FAIL");
				obj.put("MSG", "해당 에이젼시의 크레딧이 모자릅니다.");
				return obj;
			}

			credit.setInOut("OUT");
			credit.setCreditStatus(1);
			credit.setSiteIdx(loginSite.getSiteIdx());
			credit.setSiteId(loginSite.getSiteId());

		} else if ("CI".equals(credit.getCreditType())) { // 충전 신청

			long targetSiteCredit = siteService.getSiteCredit(loginSite.getUpperSiteId());
			if (targetSiteCredit < credit.getCreditAmt()) {
				obj.put("RES", "FAIL");
				obj.put("MSG", "싱으; 에이젼시의 크레딧이 모자릅니다. 상위 에이전시에 문의하세요");
				return obj;
			}

			credit.setInOut("IN");
			credit.setCreditStatus(0);

			credit.setSiteIdx(loginSite.getUpperSiteIdx());// 상위사이트아이디
			credit.setSiteId(loginSite.getUpperSiteId());

			credit.setTargetSiteIdx(loginSite.getSiteIdx()); // 타켓사이트 아이디;
			credit.setTargetSiteId(loginSite.getSiteId());

			credit.setCreditRate(loginSite.getSiteCreditRate());

		} else if ("CO".equals(credit.getCreditType())) { // 환전 신청

			if (siteCredit < credit.getCreditAmt()) {
				obj.put("RES", "FAIL");
				obj.put("MSG", "크레딧이 모자릅니다.");
				return obj;
			}

			credit.setInOut("OUT");
			credit.setCreditStatus(0);

			credit.setSiteIdx(loginSite.getUpperSiteIdx());// 상위사이트아이디
			credit.setSiteId(loginSite.getUpperSiteId());

			credit.setTargetSiteIdx(loginSite.getSiteIdx()); // 타켓사이트 아이디;
			credit.setTargetSiteId(loginSite.getSiteId());

			credit.setCreditRate(loginSite.getSiteCreditRate());

		} else if ("DP".equals(credit.getCreditType())) { // 베팅크레딧
			// credit.setInOut("OUT");
			// credit.setCreditStatus(1);

		} else if ("CD".equals(credit.getCreditType())) { // 윈머니크레딧
			// cash.setInOut("IN");
			// cash.setCreditStatus(1);
		} else if ("SDP".equals(credit.getCreditType())) { // 서브포인트충전 신청
			// cash.setInOut("IN");
			// cash.setCreditStatus(0);

			credit.setInOut("IN");
			credit.setCreditStatus(0);
			credit.setSiteIdx(loginSite.getUpperSiteIdx());// 상위사이트아이디
			credit.setSiteId(loginSite.getUpperSiteId());

			credit.setTargetSiteIdx(loginSite.getSiteIdx()); // 타켓사이트 아이디;
			credit.setTargetSiteId(loginSite.getSiteId());
			credit.setCreditRate(loginSite.getSiteCreditRate());

		} else if ("SCD".equals(credit.getCreditType())) { // 서브포인트환전 현재 없음

		}

		log.info(credit.toString());

		int res = creditService.insertCredit(credit);

		obj.put("RES", "SUCCESS");

		return obj;
	}

	@RequestMapping("/statusUpdate")
	public @ResponseBody JSONObject statusUpdate(HttpServletRequest request, ModelMap model, Credit credit)
			throws Exception {

		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();

		// enum('AI','AO','CI','CO','DP','CD','SDP','SCD')
		// inout (받는사람 기준으로 인인지 아웃인지)
		// status 바로적립 1, 승인대기 0
		// siteId 타겟사이트 아이디

		JSONObject obj = new JSONObject();
		log.info(credit.toString());

		int res = creditService.updateStatus(credit);

		obj.put("RES", "SUCCESS");

		return obj;
	}

	@GetMapping("/point")
	public String point(HttpServletRequest request, ModelMap model, @ModelAttribute("searchVO") SiteSearch search)
			throws Exception {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();
		model.put("loginSite", loginSite);
		long siteCredit = siteService.getSiteCredit(loginSite.getSiteId());
		long underSiteCredit = siteService.getUnderSiteCredit(loginSite.getSiteId());
		log.info("underSiteCredit" + underSiteCredit);
		model.put("siteCredit", siteCredit);
		model.put("underSiteCredit", underSiteCredit);
		long sitePoint = siteService.getSitePoint(loginSite.getSiteId());
		model.put("sitePoint", sitePoint);
		HashMap creditWait = siteService.getCreditWait(loginSite.getSiteIdx());
		model.put("creditWait", creditWait);
		long insureAmt = siteService.getInsureAmt(loginSite.getSiteId());
		long insurePointAmt = siteService.getInsurePointAmt(loginSite.getSiteId());
		model.put("insureAmt", insureAmt);
		model.put("insurePointAmt", insurePointAmt);

		PageFormVO pageVo = new PageFormVO();
		search.setSiteId(loginSite.getSiteId());
		search.setSiteIdx(loginSite.getSiteIdx());
		search.setCreditType("CO");

		int totalCount = creditService.getPointListCnt(search);
		if (totalCount != 0) {
			PageFormVO commonForm = new PageFormVO();
			commonForm.setFunction_name("goPage");
			commonForm.setPage(search.getPage());
			commonForm.setCount_per_page(20);
			if (search.getCount_per_list() == 0) {
				commonForm.setCount_per_list(10);
			} else {
				commonForm.setCount_per_list(search.getCount_per_list());
			}
			commonForm.setTatal_list_count(totalCount);
			pageVo = PagingUtil.setPageUtil(commonForm);
			search.setLimit(pageVo.getLimit());
			search.setOffset(pageVo.getOffset());
			search.setTatal_list_count(totalCount);

			model.put("pageInfo", pageVo.getPagination());
		}

		List<HashMap> list = creditService.getPointList(search);
		model.put("list", list);

		return "admin/applypoint";
	}

	@RequestMapping("/addPointProc")
	public @ResponseBody JSONObject addPointProc(HttpServletRequest request, ModelMap model, CreditPoint point)
			throws Exception {

		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		Site loginSite = (Site) authentication.getDetails();
		JSONObject resObj = new JSONObject();

		long sitePoint = siteService.getSitePoint(point.getTargetSiteId());
		final String LOG_PREFIX = "#-addPointProc::" + loginSite.getSiteId() + "=>" + point.getTargetSiteId() + ":::";
		long time = System.currentTimeMillis();

		log.info(LOG_PREFIX + "CreditPoint Info : " + point.toString());

		OTPInfo otpManager = siteService.getOtpInfoByManger(loginSite.getSiteIdx());
		if (otpManager == null || otpManager.getAccount().equals("")) {
			log.error(LOG_PREFIX + "OTP정보가 없습니다.");
			resObj.put("RES", "FAIL");
			resObj.put("MSG", "OTP정보가 없습니다.");
			return resObj;
		} else {
			log.info(LOG_PREFIX + "OTP Info::" + otpManager.toString());
			String secret = otpManager.getSecretKey();
			if (point.getOtp() == null || "".equals(point.getOtp())) {
				log.error(LOG_PREFIX + "OTP 번호를 입력하세요.");
				resObj.put("RES", "FAIL");
				resObj.put("MSG", "OTP 번호를 입력하세요.");
				return resObj;
			}

			boolean chkOtp = TOTPTokenGenerator.otpVerify(secret, Integer.parseInt(point.getOtp()));
			if (!chkOtp) {
				log.error(LOG_PREFIX + "OTP 번호가 일치하지 않습니다.");
				resObj.put("RES", "FAIL");
				resObj.put("MSG", "OTP 번호가 일치하지 않습니다.");
				return resObj;
			}
		}

		if ("POINT_DEPOSIT".equals(point.getVendor())) {
			// 관리자 지급
			String tranId = "POINT_DEPOSIT-" + loginSite.getSiteId() + ">" + point.getTargetSiteId() + "-" + time;
			String betId = "포인트 수동지급-" + loginSite.getSiteId() + ">" + point.getTargetSiteId() + "-" + time;
			point.setSiteIdx((long) loginSite.getSiteIdx());
			point.setSiteId(loginSite.getSiteId());
			point.setTranId(tranId);
			point.setBetId(betId);
			point.setPrePointAmt(sitePoint);

		} else if ("POINT_WITHDRAW".equals(point.getVendor())) {
			// 관리자 회수
			if (sitePoint < point.getPointAmt().intValue()) {
				resObj.put("RES", "FAIL");
				resObj.put("MSG", "해당 에이젼시의 포인트가 부족합니다.");
				return resObj;
			}
			String tranId = "POINT_WITHDRAW-" + loginSite.getSiteId() + ">" + point.getTargetSiteId() + "-" + time;
			String betId = "포인트 수동회수-" + loginSite.getSiteId() + ">" + point.getTargetSiteId() + "-" + time;
			point.setSiteIdx((long) loginSite.getSiteIdx());
			point.setSiteId(loginSite.getSiteId());
			point.setTranId(tranId);
			point.setBetId(betId);
			point.setPrePointAmt(sitePoint);
			int pointAmt = point.getPointAmt().intValue() * -1;
			point.setPointAmt(pointAmt);
		}

		log.info(LOG_PREFIX + "CreditPoint Info : " + point.toString());
		int result = creditService.insertPoint(point);
		log.info(LOG_PREFIX + "creditService.insertPoint() result : " + result);

		resObj.put("RES", "SUCCESS");

		return resObj;
	}

}
