package com.style24.front.biz.thirdparty;

import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import com.gagaframework.web.parameter.GagaMap;
import com.gagaframework.web.util.GagaDateUtil;
import com.gagaframework.web.util.GagaFileUtil;
import com.style24.core.support.env.TscConstants;
import com.style24.front.support.security.session.TsfSession;
import com.style24.persistence.domain.Customer;

import Kisinfo.Check.IPIN2Client;
import NiceID.Check.CPClient;
import lombok.extern.slf4j.Slf4j;

/**
 * 나이스 인증
 *
 * @author jsshin
 * @since 2021. 02. 05
 */
@Component
@Slf4j
public class NiceCertify {

	@Autowired
	private Environment env;

	@Value("${has-ssl}")
	private String hasSsl;

	private String niceId;			// 나이스휴대폰인증ID
	private String nicePwd;			// 나이스휴대폰인증비밀번호
	private String niceCallback;	// 나이스휴대폰인증콜백URL
	private String ipinId;			// 나이스아이핀인증ID
	private String ipinPwd;			// 나이스아이핀인증비밀번호
	private String ipinCallback;	// 나이스아이핀콜백URL
	private String domain;
	private String protocal;

	@PostConstruct
	public void init() {
		niceId = env.getProperty("certify.nice.id");
		nicePwd = env.getProperty("certify.nice.pwd");
		niceCallback = env.getProperty("certify.nice.callback");
		ipinId = env.getProperty("certify.ipin.id");
		ipinPwd = env.getProperty("certify.ipin.pwd");
		ipinCallback = env.getProperty("certify.ipin.callback");
		domain = env.getProperty("domain.front");

		boolean isSslServer = Boolean.parseBoolean(hasSsl);
		if (isSslServer) {
			protocal = "https://";
		} else {
			protocal = "http://";
		}

		log.debug("\n\n---- NiceCertify initialization started ----");
		log.debug("나이스휴대폰인증(ID: {}, PWD: {}, callback: {})", niceId, nicePwd, domain + niceCallback);
		log.debug("나이스아이핀인증(ID: {}, PWD: {}, callback: {})", ipinId, ipinPwd, domain + ipinCallback);
		log.debug("\n--- NiceCertify initialization completed ----\n");
	}

	/**
	 * 휴대폰인증 요청
	 * @return GagaMap
	 * @author jsshin
	 * @since 2021. 02. 05
	 */
	public GagaMap certifyCellPhone() {
		CPClient niceCheck = new CPClient();

		String sRequestNo = niceCheck.getRequestNO(niceId);
		log.info("sRequestNo: {}", sRequestNo);
		TsfSession.setAttribute("REQ_SEQ", sRequestNo);



		String callback = GagaFileUtil.getConcatenationPath(protocal + TsfSession.getHttpServletRequest().getServerName(), niceCallback);
		log.info("niceCallback: {}", niceCallback);

		String sAuthType = "M";	// 없으면 기본 선택화면, M: 휴대폰, C: 신용카드, X: 공인인증서
		String sPopGubun = "N";	// Y: 취소버튼 있음, N: 취소버튼 없음
		String sCustomize = "";	// 없으면 기본 웹페이지, Mobile: 모바일페이지
		String sGender = "";	//없으면 기본 선택 값, 0 : 여자, 1 : 남자

		// 입력될 plain 데이타를 만든다.
		StringBuilder sPlainData = new StringBuilder();
		sPlainData.append("7:REQ_SEQ").append(sRequestNo.getBytes().length).append(":").append(sRequestNo);
		sPlainData.append("8:SITECODE").append(niceId.getBytes().length).append(":").append(niceId);
		sPlainData.append("9:AUTH_TYPE").append(sAuthType.getBytes().length).append(":").append(sAuthType);
		sPlainData.append("7:RTN_URL").append(callback.getBytes().length).append(":").append(callback);
		sPlainData.append("7:ERR_URL").append(callback.getBytes().length).append(":").append(callback);
		sPlainData.append("11:POPUP_GUBUN").append(sPopGubun.getBytes().length).append(":").append(sPopGubun);
		sPlainData.append("9:CUSTOMIZE").append(sCustomize.getBytes().length).append(":").append(sCustomize);
		sPlainData.append("6:GENDER").append(sGender.getBytes().length).append(":").append(sGender);
		log.info("sPlainData: {}", sPlainData);

		GagaMap resultMap = new GagaMap();

		// 실제적인 암호화
		int iRtn = niceCheck.fnEncode(niceId, nicePwd, sPlainData.toString());
		log.info("iRtn: {}", iRtn);
		if (iRtn != 0) { // 실패했으면
			String errorMsg = "[" + iRtn + "]";
			if ( iRtn == -1) {
				errorMsg += "암호화 시스템 에러입니다.";
			}
			else if( iRtn == -2) {
				errorMsg += "암호화 처리오류입니다.";
			}
			else if( iRtn == -3) {
				errorMsg += "암호화 데이터 오류입니다.";
			}
			else if( iRtn == -9) {
				errorMsg += "입력 데이터 오류입니다.";
			}
			else {
				errorMsg += "알수 없는 에러 입니다.";
			}
			log.error("errorMsg : ===> {}" , errorMsg);
			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
		}

		resultMap.setInt("iRtn", iRtn);
		resultMap.setString("sEncData", niceCheck.getCipherData());

		return resultMap;
	}

	/**
	 * 휴대폰 인증 결과값
	 * @param  customer - 인증정보
	 * @return GagaMap
	 * @author jsshin
	 * @since 2021. 02. 05
	 */
	public GagaMap getCertifyCellPhoneResultInfo(Customer customer) {
		GagaMap resultMap = new GagaMap();
		String sEncData = requestReplace(customer.getEncData(),"encodeData");

		if (StringUtils.isBlank(sEncData)) {
			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
		}

		CPClient niceCheck = new CPClient();
		int iRtn = niceCheck.fnDecode(niceId, nicePwd, sEncData);
		if (iRtn != 0) {
			String errorMsg = "[" + iRtn + "]";
			if (iRtn == -1) {
				errorMsg += "복호화 시스템 오류입니다.";
			} else if (iRtn == -4) {
				errorMsg += "복호화 처리 오류입니다.";
			} else if (iRtn == -5) {
				errorMsg += "복호화 해쉬 오류입니다.";
			} else if (iRtn == -6) {
				errorMsg += "복호화 데이터 오류입니다.";
			} else if (iRtn == -9) {
				errorMsg += "입력 데이터 오류입니다.";
			} else if (iRtn == -12) {
				errorMsg += "사이트 패스워드 오류입니다.";
			} else {
				errorMsg += "결과값 확인 후, NICE신용평가정보 개발 담당자에게 문의";
			}
			log.error("errorMsg : ===> {}" , errorMsg);
			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
		}


		String sPlainData = niceCheck.getPlainData();
		String sCipherTime = niceCheck.getCipherDateTime();				// 복호화한 시간
		HashMap result = niceCheck.fnParse(sPlainData);

		log.info("휴대폰 인증 결과 값 : {}", result.toString());

		if (result == null && result.isEmpty()) {
			throw new IllegalStateException("응답값 무효 본인인증을 사용할 수 없습니다.");
		}

		String sRequestNumber = (String)result.get("REQ_SEQ");			// 요청 번호
		String sResponseNumber = (String)result.get("RES_SEQ");			// 인증 고유번호
		String sAuthType = (String)result.get("AUTH_TYPE");				// 인증 수단
		String sName = (String)result.get("NAME");						// 성명
		String sGender = (String)result.get("GENDER");					// 성별 F:여성, M:남성
		String sBirthDate = (String)result.get("BIRTHDATE");			// 생년월일(YYYYMMDD)
		String sNationalInfo = (String)result.get("NATIONALINFO");		// 내/외국인정보 0:내국인, 1:외국인
		String sDi = (String)result.get("DI");							// 중복가입 확인값 (DI_64 byte)
		String sCi = (String)result.get("CI");							// 연계정보 확인값 (CI_88 byte) 주문번호 1:1 이다.
		String sMobileNo = (String)result.get("MOBILE_NO");				// 휴대폰번호
		String sMobileCo = (String)result.get("MOBILE_CO");				// 통신사

		String sRequestNo = TsfSession.getAttribute("REQ_SEQ");	// 세션에 저장된 요청번호
		log.info("sRequestNo ===> {}, sRequestNumber ===> {}",sRequestNo ,sRequestNumber);
//		if (!sRequestNo.equals(sRequestNumber)) {
//			sResponseNumber = "";
//			sAuthType = "";
//			throw new IllegalStateException("세션값 불일치 오류 입니다.");
//		}

		String sAdult = "";		 // 미성년 : 0, 성인 : 1
		String sforeignerYn = ""; // 외국인여부(외국인:Y)

		if ("0".equals(sGender)) {
			sGender = TscConstants.Gender.FEMALE.value();
		} else if ("1".equals(sGender)) {
			sGender = TscConstants.Gender.MALE.value();
		}

		if (StringUtils.isNotBlank(sBirthDate)) {
			sAdult = this.getAdult(sBirthDate);
		}

		if ("0".equals(sNationalInfo)) {
			sforeignerYn = "N";
		} else if ("1".equals(sNationalInfo)) {
			sforeignerYn = "Y";
		}

		resultMap.setString("sAuthType", sAuthType);
		resultMap.setString("sName", sName);
		resultMap.setString("sGender", sGender);
		resultMap.setString("sBirthDate", sBirthDate);
		resultMap.setString("sforeignerYn", sforeignerYn);
		resultMap.setString("sDi", sDi);
		resultMap.setString("sCi", sCi);
		resultMap.setString("sMobileNo", sMobileNo);
		resultMap.setString("sMobileCo", sMobileCo);
		resultMap.setString("sAdult", sAdult);

		return resultMap;
	}

	/**
	 * 아이핀 인증 요청
	 * @return GagaMap
	 * @author jsshin
	 * @since 2021. 02. 09
	 */
	public GagaMap certifyIpin() {
		IPIN2Client ipinClinet = new IPIN2Client();
		String callback = GagaFileUtil.getConcatenationPath( protocal + TsfSession.getHttpServletRequest().getServerName(), ipinCallback);

		String sCPRequestNo = ipinClinet.getRequestNO(ipinId);
		TsfSession.setAttribute("CPREQUEST", sCPRequestNo);

		// 인증요청 암호화 데이터 생성
		int iRtn = ipinClinet.fnRequest(ipinId, ipinPwd, sCPRequestNo, callback);

		if (iRtn != 0) { // 실패했으면
			String errorMsg = "[" + iRtn + "]";
			if (iRtn == -1) {
				errorMsg += "암호화 시스템 오류 : 귀사 서버 환경에 맞는 모듈을 이용해주십시오." +
						"<br>오류가 지속되는 경우 iRtn 값, 서버 환경정보, 사이트코드를 기재해 문의주시기 바랍니다.";
			} else if (iRtn == -2) {
				errorMsg += "암호화 처리 오류 : 최신 모듈을 이용해주십시오. " +
						"오류가 지속되는 경우 iRtn 값, 서버 환경정보, 사이트코드를 기재해 문의주시기 바랍니다.";
			} else if (iRtn == -9) {
				errorMsg += "입력 정보 오류 : 암호화 함수에 입력된 파라미터 값을 확인해주십시오." +
						"<br>오류가 지속되는 경우, 함수 실행 직전 각 파라미터 값을 로그로 출력해 발송해주시기 바랍니다.";
			} else {
				errorMsg += "기타 오류: iRtn 값과 적용한 샘플소스를 발송해주시기 바랍니다.";
			}
			log.error("errorMsg : ===> {}" , errorMsg);
			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
		}

		GagaMap resultMap = new GagaMap();
		resultMap.setString("sEncData", ipinClinet.getCipherData());
		resultMap.setString("CPREQUEST", sCPRequestNo);
		return resultMap;
	}

	/**
	 * 아이핀 인증 결과값
	 * @param customer - 인증정보
	 * @return GagaMap
	 * @author jsshin
	 * @since 2020. 7. 15
	 */
	public GagaMap getCertifyIpinResultInfo(Customer customer) {
		GagaMap resultMap = new GagaMap();
		String sEncData = requestReplace(customer.getEncData(), "encodeData");

		if (StringUtils.isBlank(sEncData)) {
			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
		}

		IPIN2Client ipinClinet = new IPIN2Client();
		int iRtn = ipinClinet.fnResponse(ipinId, ipinPwd, sEncData);

		if (iRtn != 1) {
			String errorMsg = "[" + iRtn + "]";
			if (iRtn == -1 || iRtn == -4) {
				errorMsg +=  "복호화 시스템 오류 :<br> 귀사 서버 환경에 맞는 모듈을 이용해주십시오." +
						"<br>오류가 지속되는 경우 iRtn 값, 서버 환경정보, 사이트코드를 기재해 문의주시기 바랍니다.";
			} else if (iRtn == -6){
				errorMsg +=  "복호화 처리 오류: 당사에서 이용하는 charset인 EUC-KR이 정상적으로 받아지는 확인해주십시오. " +
						"<br>오류가 지속되는 경우, 개발 가이드의 <b>\"결과 데이터 확인 방법\"</b>을 참고해주시기 바랍니다.";
			} else if (iRtn == -9) {
				errorMsg +=  "입력 정보 오류: 복호화 함수에 입력된 파라미터 값을 확인해주십시오." +
						"<br>오류가 지속되는 경우, 함수 실행 직전 각 파라미터 값을 로그로 출력해 발송해주시기 바랍니다.";
			} else if (iRtn == -12) {
				errorMsg += "CP 패스워드 불일치: IPIN 서비스 사이트패스워드를 확인해주시기 바랍니다.";
			} else if (iRtn == -13) {
				errorMsg += "CP 요청번호 불일치: 세션에 저장된 CP요청번호(sCPRequest) 값을 확인해주시기 바랍니다.";
			} else {
				errorMsg += "기타오류: iRtn 값 확인 후 NICE평가정보 전산 담당자에게 문의해주시기 바랍니다.";
			}

			log.error("errorMsg : ===> {}" , errorMsg);
			throw new IllegalStateException("안심본인인증을 사용할 수 없습니다.");
		}

		String sVirtualNo = ipinClinet.getVNumber();		// 가상주민번호 (13자리이며, 숫자 또는 문자
		String sName = ipinClinet.getName();				// 이름 (EUC-KR)
		String sAgeCode = ipinClinet.getAgeCode();			// 연령대 코드 (개발 가이드 참조)
		String sGenderCode = ipinClinet.getGenderCode();	// 성별 코드 (0:여성, 1: 남성)
		String sBirthDate = ipinClinet.getBirthDate();		// 생년월일 (YYYYMMDD)
		String sForeigner = ipinClinet.getNationalInfo();	// 내/외국인코드 (0:내국인, 1:외국인)
		String sCPRequestNum = ipinClinet.getCPRequestNO();	// CP 요청번호
		String sDupInfo = ipinClinet.getDupInfo();			// 중복가입확인값 (64byte, 개인식별값, DI:Duplicate Info)
		String sConnInfo = ipinClinet.getCoInfo1();			// 연계정보 확인값 (88byte, 개인식별값, CI:Connecting Information)
		String sCIUpdate = ipinClinet.getCIUpdate();		// CI 갱신정보 (1~: 가이드 참조)
		String sAuthInfo = ipinClinet.getAuthInfo();		// 본인확인수단 (0~4: 가이드 참조)


		String sCPRequestNo = TsfSession.getAttribute("CPREQUEST");
//		if (!sCPRequestNo.equals(sCPRequestNum)) {
//			throw new IllegalStateException("세션값 불일치 오류 입니다.");
//		}

		String sGender = "";
		String sAdult = "N"; //미성년자
		String sforeignerYn = "";

		if (Integer.parseInt(sAgeCode) > 3) {
			sAdult = "Y";//성인
		}
		if ("0".equals(sGenderCode)) {
			sGender = TscConstants.Gender.FEMALE.value();
		} else if ("1".equals(sGenderCode)) {
			sGender = TscConstants.Gender.MALE.value();
		}

		if ("0".equals(sForeigner)) {
			sforeignerYn = "N";
		} else if ("1".equals(sForeigner)) {
			sforeignerYn = "Y";
		}

		resultMap.setString("sVirtualNo", sVirtualNo);
		resultMap.setString("sName", sName);
		resultMap.setString("sGender", sGender);
		resultMap.setString("sBirthDate", sBirthDate);
		resultMap.setString("sforeignerYn", sforeignerYn);
		resultMap.setString("sDupInfo", sDupInfo);
		resultMap.setString("sConnInfo", sConnInfo);
		resultMap.setString("sAdult", sAdult);

		return resultMap;
	}


	/**
	 * 성인여부
	 * @param  birthDate
	 * @return String 성인:Y , 미성년자:N
	 * @author jsshin
	 * @since 2021. 02. 05
	 */
	private String getAdult(String birthDate) {
		Date time = new Date();
		Calendar cal = Calendar.getInstance();
		cal.setTime(time);
		cal.add(Calendar.YEAR, -13);

		Date limitDate = cal.getTime();
		Date birthDt = GagaDateUtil.getDate(birthDate, "yyyyMMdd");

		int compareDt = limitDate.compareTo(birthDt);

		String sAdult = "Y"; //성인
		if (compareDt < 0) {
			sAdult = "N"; //미성년자
		}

		return sAdult;
	}

	public String requestReplace (String paramValue, String gubun) {

		String result = "";

		if (paramValue != null) {

			paramValue = paramValue.replaceAll("<", "&lt;").replaceAll(">", "&gt;");

			paramValue = paramValue.replaceAll("\\*", "");
			paramValue = paramValue.replaceAll("\\?", "");
			paramValue = paramValue.replaceAll("\\[", "");
			paramValue = paramValue.replaceAll("\\{", "");
			paramValue = paramValue.replaceAll("\\(", "");
			paramValue = paramValue.replaceAll("\\)", "");
			paramValue = paramValue.replaceAll("\\^", "");
			paramValue = paramValue.replaceAll("\\$", "");
			paramValue = paramValue.replaceAll("'", "");
			paramValue = paramValue.replaceAll("@", "");
			paramValue = paramValue.replaceAll("%", "");
			paramValue = paramValue.replaceAll(";", "");
			paramValue = paramValue.replaceAll(":", "");
			paramValue = paramValue.replaceAll("-", "");
			paramValue = paramValue.replaceAll("#", "");
			paramValue = paramValue.replaceAll("--", "");
			paramValue = paramValue.replaceAll("-", "");
			paramValue = paramValue.replaceAll(",", "");

			if(!"encodeData".equals(gubun)){
				paramValue = paramValue.replaceAll("\\+", "");
				paramValue = paramValue.replaceAll("/", "");
				paramValue = paramValue.replaceAll("=", "");
			}

			result = paramValue;

		}
		return result;
	}


}
