package com.style24.front.biz.web;

import java.io.IOException;
import java.math.BigInteger;
import java.security.SecureRandom;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.style24.core.support.env.TscConstants;
import com.style24.core.support.message.TscMessageByLocale;
import com.style24.front.biz.service.TsfCustomerService;
import com.style24.front.biz.thirdparty.GoogleReCaptcha;
import com.style24.front.biz.thirdparty.KaKaoLogin;
import com.style24.front.biz.thirdparty.NaverLogin;
import com.style24.front.biz.thirdparty.Yes24Login;
import com.style24.front.support.controller.TsfBaseController;
import com.style24.front.support.security.session.TsfSession;
import com.style24.persistence.domain.CustSnsInfo;
import com.style24.persistence.domain.Customer;

import lombok.extern.slf4j.Slf4j;

import com.gagaframework.web.parameter.GagaMap;

/**
 * Index Controller
 * 
 * @author gagamel
 * @since 2020. 9. 11
 */
@Controller
@Slf4j
public class TsfIndexController extends TsfBaseController {

	@Autowired
	private Environment env;

	@Autowired
	private TscMessageByLocale message;

	@Autowired
	private TsfCustomerService customerService;

	@Autowired
	private KaKaoLogin kakaoLogin;

	@Autowired
	private NaverLogin naverLogin;

	@Autowired
	private Yes24Login yes24Login;

	@Autowired
	private GoogleReCaptcha googleReCaptcha;

	@Autowired
	private ObjectMapper objectMapper;

	/**
	 * 시스템점검중 페이지
	 * @return
	 * @author gagamel
	 * @since 2020. 3. 29
	 */
	@GetMapping("/system/check")
	public String systemCheck() {
		return super.getDeviceViewName("error/SystemCheck");
	}

	/**
	 * 첫 페이지
	 * @return
	 * @author gagamel
	 * @since 2020. 2. 3
	 */
	@GetMapping("/")
	public String index() {
		return "forward:/display/mall/main/form";
	}

	/**
	 * 로그인 페이지
	 *
	 * @param isError - 오류여부
	 * @param session - HttpSession
	 * @return ModelAndView
	 * @author gagamel
	 * @throws IOException
	 * @since 2020. 2. 4
	 */
	@GetMapping("/signin")
	public ModelAndView signin(@RequestParam(value = "error", required = false) boolean isError, HttpSession session, HttpServletResponse response) throws IOException {
		ModelAndView mav = new ModelAndView();

		if (TsfSession.isLogin()) {
			response.sendRedirect("/");
		}

		log.debug("isError: {}", isError);

		if (isError) {
			Exception e = (Exception)session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
			log.debug("e.getMessage(): {}", e.getMessage());
			mav.addObject("error", e.getMessage());
		}

		mav.addObject("front", env.getProperty("domain.front"));
		mav.addObject("sitekey", env.getProperty("google.sitekey"));
		mav.addObject("ipAddress", TsfSession.getIpAddress());

		mav.setViewName(super.getDeviceViewName("SigninForm"));


		return mav;
	}

	/**
	 * 카카오 로그인 페이지 호출
	 *
	 * @return String
	 * @author jsshin
	 * @since 2021. 02. 23
	 */
	@GetMapping("/signin/kakologin")
	public String signinKaKaoLogin(@RequestParam(value = "rememberMe", required = false) String rememberMe, @RequestParam(value = "requestGb", required = false) String requestGb) {
//		if (StringUtils.isNotBlank(rememberMe)) {
//			// RememberMe 세션 저장
//			TsfSession.setAttribute("rememberMe", rememberMe);
//		}
		TsfSession.setAttribute("rememberMe", "true");

		// CSRF 방지를 위한 상태 토큰 생성 코드
		SecureRandom random = new SecureRandom();
		String state = new BigInteger(130, random).toString(32);
		state += "!@!" + requestGb;
		TsfSession.setAttribute("state", state);

		String redirectUrl = kakaoLogin.getAuthorizeUrl(state);

		return "redirect:" + redirectUrl;
	}

	/**
	 * 네이버 로그인 페이지 호출
	 *
	 * @return String
	 * @author jsshin
	 * @since 2021. 02. 23
	 */
	@GetMapping("/signin/naverlogin")
	public String signinNaverLogin(@RequestParam(value = "rememberMe", required = false) String rememberMe, @RequestParam(value = "requestGb", required = false) String requestGb) {
//		if (StringUtils.isNotBlank(rememberMe)) {
//			// RememberMe 세션 저장
//			TsfSession.setAttribute("rememberMe", rememberMe);
//		}
		TsfSession.setAttribute("rememberMe", "true");

		// CSRF 방지를 위한 상태 토큰 생성 코드
		SecureRandom random = new SecureRandom();
		String state = new BigInteger(130, random).toString(32);
		state += "!@!" + requestGb;
		TsfSession.setAttribute("state", state);

		String redirectUrl = naverLogin.getAuthorizeUrl(state);

		return "redirect:" + redirectUrl;
	}

	/**
	 * YES24 로그인 페이지 호출
	 *
	 * @return String
	 * @author jsshin
	 * @since 2021. 02. 23
	 */
	@GetMapping("/signin/yes24login")
	public String signinYes24Login(@RequestParam(value = "rememberMe", required = false) String rememberMe, @RequestParam(value = "requestGb", required = false) String requestGb) {
//		if (StringUtils.isNotBlank(rememberMe)) {
//			// RememberMe 세션 저장
//			TsfSession.setAttribute("rememberMe", rememberMe);
//		}
		TsfSession.setAttribute("rememberMe", "true");

		// CSRF 방지를 위한 상태 토큰 생성 코드
		SecureRandom random = new SecureRandom();
		String state = new BigInteger(130, random).toString(32);
		state += "!@!" + requestGb;
		TsfSession.setAttribute("state", state);

		String redirectUrl = yes24Login.getAuthorizeUrl(state);

		return "redirect:" + redirectUrl;
	}

	/**
	 * SNS 로그인 콜백
	 *
	 * @param session - HttpSession
	 * @param snsType - SNS유형(NV:네이버, KK:카카오)
	 * @return ModelAndView
	 * @author jsshin
	 * @since 2021. 02. 23
	 */
	@RequestMapping("/signin/snsLoginCallback")
	public ModelAndView signinSnsLoginCallback(@RequestParam(value = "snsType", required = false) String snsType, @RequestParam(value = "code", required = false) String code, @RequestParam(value = "state", required = false) String state, @RequestParam(value = "error", required = false) boolean isError, HttpSession session, HttpServletRequest request) {
		ModelAndView mav = new ModelAndView();

		log.info("isError: {}", isError);

		if (isError) {
			Exception ex = (Exception)session.getAttribute("SPRING_SECURITY_LAST_EXCEPTION");
			log.debug("e.getMessage(): {}", ex.getMessage());
			mav.addObject("error", ex.getMessage());
		}

		// 로그인이 된 상태로 콜백진입시 메인이동
		boolean isLogin = TsfSession.isLogin();
		if (isLogin) {
			mav.setViewName("redirect:/");
			return mav;
		}

		GagaMap userInfo = new GagaMap();
		boolean isSnsLoing = false;
		if (StringUtils.isNotBlank(code) && TscConstants.SnsType.KAKAO.value().equals(snsType)) {
			String sessionState = TsfSession.getAttribute("state");
			if (sessionState.equals(state)) {
				GagaMap tokenInfo = kakaoLogin.getAccessTocken(code, state);
				userInfo = kakaoLogin.getKakaoUserInfo(tokenInfo.getString("access_token"));
				userInfo.setString("accessToken", tokenInfo.getString("access_token"));
				userInfo.setString("refreshToken", tokenInfo.getString("refresh_token"));
				userInfo.setString("snsType", snsType);
				userInfo.setString("requestGb", tokenInfo.getString("requestGb"));
				isSnsLoing = true;
			}
		}

		if (StringUtils.isNotBlank(code) && TscConstants.SnsType.NAVER.value().equals(snsType)) {
			String sessionState = TsfSession.getAttribute("state");
			if (sessionState.equals(state)) {
				GagaMap tokenInfo = naverLogin.getAccessTocken(code, state);
				userInfo = naverLogin.getNaverUserInfo(tokenInfo.getString("access_token"));
				userInfo.setString("accessToken", tokenInfo.getString("access_token"));
				userInfo.setString("refreshToken", tokenInfo.getString("refresh_token"));
				userInfo.setString("snsType", snsType);
				userInfo.setString("requestGb", tokenInfo.getString("requestGb"));
				isSnsLoing = true;
			}
		}

		// SNS 로그인 성공시 정보 세션 저장
		GagaMap resultMap = new GagaMap();
		if (isSnsLoing) {
			CustSnsInfo custSnsInfo = objectMapper.convertValue(userInfo, CustSnsInfo.class);
			//log.info("custSnsInfo ==> {}", custSnsInfo.toString());

			//SNS 로그인 처리
			resultMap = customerService.customerSnsProcessing(custSnsInfo);
			resultMap.setString("snsId", custSnsInfo.getSnsId());
			resultMap.setString("snsType", custSnsInfo.getSnsType());

			String custStat = resultMap.getString("custStat");

			// 신규가입 이면 바로 로그인 처리
			if ("NEW_CUST".equals(custStat)) {
				customerService.getLogin(Integer.parseInt(resultMap.getString("custNo")), request);
			}

			// 가입 폼으로 이동
			if ("EMPTY_PHONE_CUST".equals(custStat)) {
				session.setAttribute("custSnsInfo", custSnsInfo);
			}
		} else {
			resultMap.setString("custStat", "FAIL_CUST");
		}

		mav.addObject("resultMap", resultMap);

		mav.setViewName(super.getDeviceViewName("SnsCallBackForm"));

		return mav;
	}

	/**
	 * SNS - YES24 로그인 콜백URL
	 *
	 * @param ipin - Yes24넘겨 주는 암호화된 값:날짜|CI
	 * @param session - Yes24넘겨받은 정보 세션저장
	 * @return ModelAndView
	 * @author jsshin
	 * @since 2021. 02. 23
	 */
	@RequestMapping("/signin/yes24LoginCallback")
	public ModelAndView yes24LoginCallback(@RequestParam(value = "ipin", required = false) String ipin, @RequestParam(value = "ipn", required = false) String ipn, HttpSession session) {
		ModelAndView mav = new ModelAndView();
		boolean isSnsLoing = false;
		GagaMap userInfo = new GagaMap();

		String encryData = StringUtils.isNotBlank(ipin) ? ipin : ipn;

		if (StringUtils.isNotBlank(encryData)) {
			userInfo = yes24Login.getUserInfo(encryData);
			userInfo.setString("snsType", TscConstants.SnsType.YES24.value());
			isSnsLoing = true;
		}

		GagaMap resultMap = new GagaMap();

		// SNS 로그인 성공시 정보 세션 저장
		if (isSnsLoing) {
			CustSnsInfo custSnsInfo = objectMapper.convertValue(userInfo, CustSnsInfo.class);
			//log.info("custSnsInfo ==> {}", custSnsInfo.toString());
			resultMap.setString("snsId", custSnsInfo.getSnsId());
			resultMap.setString("snsType", custSnsInfo.getSnsType());

			Customer custInfo = customerService.getCusomterSnsFind(custSnsInfo);

			if (custInfo != null) {
				resultMap.setString("custStat", "SUCC_CUST");
			} else {
				session.setAttribute("custSnsInfo", custSnsInfo);
				resultMap.setString("custNm", custSnsInfo.getCustNm());
				resultMap.setString("custStat", "NEED_AGREE_CUST");
			}

		} else {
			resultMap.setString("custStat", "FAIL_CUST");
		}

		mav.addObject("resultMap", resultMap);
		mav.setViewName(super.getDeviceViewName("SnsCallBackForm"));

		return mav;
	}

	/**
	 * 구글 리캡챠 확인
	 *
	 * @param request - HttpServletRequest
	 * @return GagaMap
	 * @author jsshin
	 * @since 2021. 03. 31
	 */
	@PostMapping("/verify/recaptcha")
	@ResponseBody
	public GagaMap verfyRecaptcha(HttpServletRequest request) {
		String token = request.getParameter("token");
		log.info("token {}", token);
		return googleReCaptcha.getVerify(token);
	}

}
