package itn.com.cmm.util;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Hex;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.stereotype.Component;

import egovframework.rte.fdl.idgnr.EgovIdGnrService;
import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
import itn.com.cmm.LoginVO;
import itn.com.cmm.util.MJUtil;
import itn.com.utl.fcc.service.EgovStringUtil;
import itn.let.mjo.event.service.MjonEventVO;
import itn.let.mjo.event.service.impl.MjonEventDAO;
import itn.let.mjo.msgdata.service.MjonMsgDataService;
import itn.let.mjo.pay.service.MjonPayVO;
import itn.let.mjo.pay.service.impl.MjonPayDAO;
import itn.let.mjo.tax.service.TaxVO;
import itn.let.mjo.tax.service.impl.TaxDAO;
import itn.let.sym.site.service.JoinSettingVO;
import itn.let.uat.uia.service.impl.MberManageDAO;
import itn.let.uss.umt.service.MberManageVO;

@Component("nicePayUtil")
public class NicePayUtil {
	
	@Resource(name = "egovMjonCashIdGnrService")
    private EgovIdGnrService idgenMjonCashId;
	
	@Resource(name = "egovMjonPointIdGnrService")
    private EgovIdGnrService idgenMjonPointId;
	
	@Resource(name = "MjonMsgDataService")
    private MjonMsgDataService mjonMsgDataService;
	
	/**
	 * @param mjonPayVO
	 * @param request
	 * @return
	 * @throws Exception
	 * //nicepay 정상 결제 여부 확인
	 */
	public boolean pgAuth(MjonPayVO mjonPayVO , HttpServletRequest request) throws Exception {
		
		//Pg 결제 정상여부 체크
		boolean paySuccess = false;
		
		/*
		****************************************************************************************
		* <인증 결과 파라미터>
		****************************************************************************************
		*/
		String authResultCode 	= (String)request.getParameter("AuthResultCode"); 	// 인증결과 : 0000(성공)
		String authResultMsg 	= (String)request.getParameter("AuthResultMsg"); 	// 인증결과 메시지
		String nextAppURL 		= (String)request.getParameter("NextAppURL"); 		// 승인 요청 URL
		String txTid 			= (String)request.getParameter("TxTid"); 			// 거래 ID
		String authToken 		= (String)request.getParameter("AuthToken"); 		// 인증 TOKEN
		String payMethod 		= (String)request.getParameter("PayMethod"); 		// 결제수단
		String mid 				= (String)request.getParameter("MID"); 				// 상점 아이디
		String moid 			= (String)request.getParameter("Moid"); 			// 상점 주문번호
		String amt 				= (String)request.getParameter("Amt"); 				// 결제 금액
		String reqReserved 		= (String)request.getParameter("ReqReserved"); 		// 상점 예약필드
		String netCancelURL 	= (String)request.getParameter("NetCancelURL"); 	// 망취소 요청 URL
		/*
		****************************************************************************************
		* <승인 결과 파라미터 정의>
		* 샘플페이지에서는 승인 결과 파라미터 중 일부만 예시되어 있으며, 
		* 추가적으로 사용하실 파라미터는 연동메뉴얼을 참고하세요.
		****************************************************************************************
		*/
		String ResultCode 	= ""; String ResultMsg 	= ""; String PayMethod 	= "";
		String GoodsName 	= ""; String Amt 		= ""; String TID 		= "";
		String cardCode		= ""; 		// 결제카드사코드
		String cardName		= ""; 		// 결제카드사명
		String bankCode		= "";		// 결제은행코드
		String bankName		= "";		// 결제은행명
		
		/*
		****************************************************************************************
		* <인증 결과 성공시 승인 진행>
		****************************************************************************************
		*/
		
		String resultJsonStr = "";
		if(authResultCode.equals("0000")){
			/*
			****************************************************************************************
			* <해쉬암호화> (수정하지 마세요)
			* SHA-256 해쉬암호화는 거래 위변조를 막기위한 방법입니다. 
			****************************************************************************************
			*/
			DataEncrypt sha256Enc 	= new DataEncrypt();
			String merchantKey 		= "7wnkxZbHvIA7FoCc6jF8IcXU+Wd3sn5BcMHuWJROe53AjRKnC6CistVdVZwrUKCCdaF+dAx230bwHSQ/E29RWA=="; // 운영상점키
			//String merchantKey 		= "EYzu8jGGMfqaDEp76gSckuvnaHHu+bC4opsSN6lHv3b2lurNYkVXrZ7Z1AoqQnXI3eLuaUFyoRNC6FkrzVjceg=="; // 테스트 상점키
			String ediDate			= getyyyyMMddHHmmss();
			String signData 		= sha256Enc.encrypt(authToken + mid + amt + ediDate + merchantKey);
			
			/*
			****************************************************************************************
			* <승인 요청>
			* 승인에 필요한 데이터 생성 후 server to server 통신을 통해 승인 처리 합니다.
			****************************************************************************************
			*/
			StringBuffer requestData = new StringBuffer();
			requestData.append("TID=").append(txTid).append("&");
			requestData.append("AuthToken=").append(authToken).append("&");
			requestData.append("MID=").append(mid).append("&");
			requestData.append("Amt=").append(amt).append("&");
			requestData.append("EdiDate=").append(ediDate).append("&");
			requestData.append("SignData=").append(signData);

			try {
				resultJsonStr = connectToServer(requestData.toString(), nextAppURL);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			HashMap resultData = new HashMap();
			
			if("9999".equals(resultJsonStr)){
				/*
				*************************************************************************************
				* <망취소 요청>
				* 승인 통신중에 Exception 발생시 망취소 처리를 권고합니다.
				*************************************************************************************
				*/
				StringBuffer netCancelData = new StringBuffer();
				requestData.append("&").append("NetCancel=").append("1");
				String cancelResultJsonStr = connectToServer(requestData.toString(), netCancelURL);
				
				HashMap cancelResultData = jsonStringToHashMap(cancelResultJsonStr);
				ResultCode = (String)cancelResultData.get("ResultCode");
				ResultMsg = (String)cancelResultData.get("ResultMsg");
			}else{
				resultData = jsonStringToHashMap(resultJsonStr);
				ResultCode 	= (String)resultData.get("ResultCode");	// 결과코드 (정상 결과코드:3001)
				ResultMsg 	= (String)resultData.get("ResultMsg");	// 결과메시지
				PayMethod 	= (String)resultData.get("PayMethod");	// 결제수단
				GoodsName   = (String)resultData.get("GoodsName");	// 상품명
				Amt       	= (String)resultData.get("Amt");		// 결제 금액
				TID       	= (String)resultData.get("TID");		// 거래번호
				cardCode	= (String)resultData.get("CardCode"); 	// 결제카드사코드
				cardName	= (String)resultData.get("CardName"); 	// 결제카드사명
				bankCode	= (String)resultData.get("BankCode"); 	// 결제은행코드
				bankName	= (String)resultData.get("BankName"); 	// 결제은행명
				/*
				*************************************************************************************
				* <결제 성공 여부 확인>
				*************************************************************************************
				*/
				if(PayMethod != null){
					if(PayMethod.equals("CARD")){
						if(ResultCode.equals("3001")) paySuccess = true; // 신용카드(정상 결과코드:3001)       	
					}else if(PayMethod.equals("BANK")){
						if(ResultCode.equals("4000")) paySuccess = true; // 계좌이체(정상 결과코드:4000)	
					}else if(PayMethod.equals("CELLPHONE")){
						if(ResultCode.equals("A000")) paySuccess = true; // 휴대폰(정상 결과코드:A000)	
					}else if(PayMethod.equals("VBANK")){
						if(ResultCode.equals("4100")) paySuccess = true; // 가상계좌(정상 결과코드:4100)
					}else if(PayMethod.equals("SSG_BANK")){
						if(ResultCode.equals("0000")) paySuccess = true; // SSG은행계좌(정상 결과코드:0000)
					}else if(PayMethod.equals("CMS_BANK")){
						if(ResultCode.equals("0000")) paySuccess = true; // 계좌간편결제(정상 결과코드:0000)
					}
				}
			}
		}else{
			ResultCode 	= authResultCode; 	
			ResultMsg 	= authResultMsg;
		}
		
		//PG테이블 변수설정  오류시에도 PG테이블에 값 insert 
		mjonPayVO.setPgStatus("4"); //결제오류
		mjonPayVO.setResultCode(authResultCode);
		mjonPayVO.setResultMsg(ResultMsg); //'결과메시지',
		mjonPayVO.setTid(txTid); // 거래 ID
		mjonPayVO.setPayMethod(payMethod); // 결제수단
		mjonPayVO.setMid(mid);  // 상점 아이디
		mjonPayVO.setAmt(amt); // 결제 금액
		mjonPayVO.setPgCode("INNOPAY"); //이노페이(강제세팅)
		LoginVO	loginVO = (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser();
    	String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
//    	userId = mjonPayVO.getMoid() ;  //테스트시 화면에서 전송한 고객사 ID
//    	mjonPayVO.setMoid(idgenPgMoid.getNextStringId()); // 상점 주문번호 결제 완료  후 생성 
    	mjonPayVO.setRegNo(mjonPayVO.getBuyerTel());  // '사업자번호/전화번호',
		mjonPayVO.setMobile(mjonPayVO.getBuyerTel());  // '사업자번호/전화번호',
		mjonPayVO.setPhone(mjonPayVO.getBuyerTel()); //연락처
		mjonPayVO.setEmail(mjonPayVO.getBuyerEmail()); //이메일
		mjonPayVO.setRepName(mjonPayVO.getBuyerName());  //'대표자명',
		mjonPayVO.setConfirmYn("N"); //'완료여부',
		mjonPayVO.setUserId(userId);
		mjonPayVO.setFrstRegisterId(userId);
		mjonPayVO.setCardCode(cardCode);	//결제카드사코드
		mjonPayVO.setCardName(cardName);	//결제카드사명 
		mjonPayVO.setBankCode(bankCode);	//결제은행코드
		mjonPayVO.setBankName(bankName);	//결제은행사명
		
		if(!paySuccess) {
			return false;
		}
		
		//PG테이블 변수 설정--------------------------------------------------------------------------------
		if("0000".equals(authResultCode)) { // 인증결과 : 0000(성공)
			mjonPayVO.setPgStatus("1"); //'결제 상태 - 0:입금대기, 1:결제완료, 4:결제오류, 9:취소완료'
			mjonPayVO.setResultCode(authResultCode); //결과코드
		}
		
		return paySuccess ;
	}
	
	//server to server 통신
	public String connectToServer(String data, String reqUrl) throws Exception{
		HttpURLConnection conn 		= null;
		BufferedReader resultReader = null;
		PrintWriter pw 				= null;
		URL url 					= null;
		
		int statusCode = 0;
		StringBuffer recvBuffer = new StringBuffer();
		try{
			url = new URL(reqUrl);
			conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("POST");
			conn.setConnectTimeout(3000);
			conn.setReadTimeout(5000);
			conn.setDoOutput(true);
			
			pw = new PrintWriter(conn.getOutputStream());
			pw.write(data);
			pw.flush();
			
			statusCode = conn.getResponseCode();
			resultReader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "euc-kr"));
			for(String temp; (temp = resultReader.readLine()) != null;){
				recvBuffer.append(temp).append("\n");
			}
			
			if(!(statusCode == HttpURLConnection.HTTP_OK)){
				throw new Exception();
			}
			
			return recvBuffer.toString().trim();
		}catch (Exception e){
			return "9999";
		}finally{
			recvBuffer.setLength(0);
			
			try{
				if(resultReader != null){
					resultReader.close();
				}
			}catch(Exception ex){
				resultReader = null;
			}
			
			try{
				if(pw != null) {
					pw.close();
				}
			}catch(Exception ex){
				pw = null;
			}
			
			try{
				if(conn != null) {
					conn.disconnect();
				}
			}catch(Exception ex){
				conn = null;
			}
		}
	}
	
	//JSON String -> HashMap 변환
	public static HashMap jsonStringToHashMap(String str) throws Exception{
		HashMap dataMap = new HashMap();
		JSONParser parser = new JSONParser();
		try{
			Object obj = parser.parse(str);
			JSONObject jsonObject = (JSONObject)obj;

			Iterator<String> keyStr = jsonObject.keySet().iterator();
			while(keyStr.hasNext()){
				String key = keyStr.next();
				Object value = jsonObject.get(key);
				
				dataMap.put(key, value);
			}
		}catch(Exception e){
			
		}
		return dataMap;
	}
	
	public final synchronized String getyyyyMMddHHmmss(){
		SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");
		return yyyyMMddHHmmss.format(new Date());
	}
	
	// SHA-256 형식으로 암호화
	public class DataEncrypt{
		MessageDigest md;
		String strSRCData = "";
		String strENCData = "";
		String strOUTData = "";
		
		public DataEncrypt(){ }
		public String encrypt(String strData){
			String passACL = null;
			MessageDigest md = null;
			try{
				md = MessageDigest.getInstance("SHA-256");
				md.reset();
				md.update(strData.getBytes());
				byte[] raw = md.digest();
				passACL = encodeHex(raw);
			}catch(Exception e){
				System.out.print("암호화 에러" + e.toString());
			}
			return passACL;
		}
		
		public String encodeHex(byte [] b){
			char [] c = Hex.encodeHex(b);
			return new String(c);
		}
	}
	
	// 세금 값 넣기
	public MjonPayVO setTexVO(MjonPayVO mjonPayVO) throws Exception{
		/*
		 * amt = mjonPayVO.setAmt(amt); // 결제 금액
		 * userId = mjonPayVO.getMoid() ;  //테스트시 화면에서 전송한 고객사 ID
		 * mjonPayVO.setPayMethod(payMethod); // 결제수단
		 */
		 
		String s_amt = mjonPayVO.getAmt();
		// 부가세별도 충전금액
		s_amt = setCashVatNotIncluded(s_amt);
		
		String s_user_id = mjonPayVO.getMoid();
		 
		//PG Tax테이블  변수 생성
		mjonPayVO.setRcptType("9"); //PG결제는 세금계산서 '발행유형-[PG결제-현금영수증 유형과 동일] 1:소득공제, 2:지출증빙, 9:세금계산서', (확인필요)
		
		mjonPayVO.setRegNo(mjonPayVO.getBuyerTel());  // '사업자번호/전화번호',
		mjonPayVO.setMobile(mjonPayVO.getBuyerTel());  // '사업자번호/전화번호',
		mjonPayVO.setPhone(mjonPayVO.getBuyerTel()); //연락처
		mjonPayVO.setEmail(mjonPayVO.getBuyerEmail()); //이메일
		mjonPayVO.setRepName(mjonPayVO.getBuyerName());  //'대표자명',
		mjonPayVO.setConfirmYn("Y"); //'완료여부',
		
		//캐쉬 테이블 변수 생성
		mjonPayVO.setCashId(idgenMjonCashId.getNextStringId()) ;
		mjonPayVO.setPointId(idgenMjonPointId.getNextStringId()) ;
		mjonPayVO.setCash(Float.parseFloat(s_amt)); //'사용 캐쉬-양수:지급, 음수:소모',
		
		mjonPayVO.setOrderId(mjonPayVO.getMoid());  //'주문번호-주문번호가 없으면 관리자 임의 지급',
		
		mjonPayVO.setUserId(s_user_id);
		mjonPayVO.setFrstRegisterId(s_user_id);
		
		return mjonPayVO;
	}
	
	// 부가세별도 충전금액
	private String setCashVatNotIncluded(String val) {
		String rtnVal = "";
		
		// 공급대가 = 공급가액(공급대가/11*10) + 부가세(공급대가/11)
		// 11000 = (11000/11*10 ) + 11000/11
		// 공급가액 계산로직
		rtnVal = Math.round(Float.parseFloat(val) / 11 * 10) + "";
		
		return rtnVal;
	}
	
	//cash 값 넣기
	/**
	 * @param mjonPayVO
	 * @return
	 * @throws Exception
	 * cash table 값 넣기
	 */
	public MjonPayVO setCashVO(MjonPayVO mjonPayVO) throws Exception{
		/*
		 * amt = mjonPayVO.setAmt(amt); // 결제 금액
		 * userId = mjonPayVO.getMoid() ;  //테스트시 화면에서 전송한 고객사 ID
		 * mjonPayVO.setPayMethod(payMethod); // 결제수단
		 */
		 
		String s_amt = mjonPayVO.getAmt();
		// 부가세별도 충전금액
		s_amt = setCashVatNotIncluded(s_amt);
			
		String s_user_id = mjonPayVO.getMoid();
		 
			//캐쉬 테이블 변수 생성
			mjonPayVO.setCashId(idgenMjonCashId.getNextStringId()) ;
			mjonPayVO.setPointId(idgenMjonPointId.getNextStringId()) ;
			mjonPayVO.setCash(Float.parseFloat(s_amt)); //'사용 캐쉬-양수:지급, 음수:소모',
			
			mjonPayVO.setOrderId(mjonPayVO.getMoid());  //'주문번호-주문번호가 없으면 관리자 임의 지급',
			
			mjonPayVO.setUserId(s_user_id);
			mjonPayVO.setFrstRegisterId(s_user_id);
			
			
			String s_paymethod = mjonPayVO.getPayMethod();
			
			if(s_paymethod.equals("CARD")){
				s_paymethod = "신용카드" ; // 신용카드(정상 결과코드:3001)       	
			}else if(s_paymethod.equals("BANK")){
				s_paymethod = "계좌이체" ; // 계좌이체(정상 결과코드:4000)	
			}else if(s_paymethod.equals("CELLPHONE")){
				s_paymethod = "휴대폰" ; // 휴대폰(정상 결과코드:A000)	 
			}else if(s_paymethod.equals("VBANK")){
				s_paymethod = "가상계좌" ; // 가상계좌(정상 결과코드:4100)
			}else if(s_paymethod.equals("SSG_BANK")){
				s_paymethod = "SSG은행계좌" ; // SSG은행계좌(정상 결과코드:0000)
			}else if(s_paymethod.equals("CMS_BANK")){
				s_paymethod = "계좌간편결제" ; // 계좌간편결제(정상 결과코드:0000)
			}else {
				s_paymethod = "";
			}
			
			String memo = s_paymethod + " " + s_amt + " 충전" ;
			mjonPayVO.setMemo(memo); //캐쉬메모
		
		return mjonPayVO;
	}
	
	//point 값 넣기
	/**
	 * @param mjonPayVO
	 * @return
	 * @throws Exception
	 * point table 값 넣기
	 */
	public MjonPayVO setPointVO(MjonPayVO mjonPayVO) throws Exception{
			
			String s_paymethod = mjonPayVO.getPayMethod();
			if(s_paymethod.equals("CARD")){
				s_paymethod = "신용카드" ; // 신용카드(정상 결과코드:3001)       	
			}else if(s_paymethod.equals("SPAY")){
				s_paymethod = "간편결제" ; // 간편결제	
			}else if(s_paymethod.equals("BANK")){
				s_paymethod = "계좌이체" ; // 계좌이체(정상 결과코드:4000)	
			}else if(s_paymethod.equals("CELLPHONE")){
				s_paymethod = "휴대폰" ; // 휴대폰(정상 결과코드:A000)	 
			}else if(s_paymethod.equals("VBANK")){
				s_paymethod = "가상계좌" ; // 가상계좌(정상 결과코드:4100)
			}else if(s_paymethod.equals("SSG_BANK")){
				s_paymethod = "SSG은행계좌" ; // SSG은행계좌(정상 결과코드:0000)
			}else if(s_paymethod.equals("CMS_BANK")){
				s_paymethod = "계좌간편결제" ; // 계좌간편결제(정상 결과코드:0000)
			}else {
				s_paymethod = "";
			}			
			
			String s_amt = mjonPayVO.getAmt();
			// 부가세별도 충전금액
			s_amt = setCashVatNotIncluded(s_amt);
			
			//포인트 테이블 변수설정
			JoinSettingVO sysJoinSetVO = mjonMsgDataService.selectJoinSettingInfo();			
			//int point = Math.round( (Float.parseFloat(s_amt)*2/100) ) ;
			float p_i_re_point = 0; 
			if (sysJoinSetVO != null) {
				p_i_re_point = sysJoinSetVO.getPointPer();
			}
			int point = Math.round((Float.parseFloat(s_amt)*p_i_re_point/100)) ;
			
			mjonPayVO.setPoint(point);
			
			String pointMemo = s_paymethod; //포인트 메모
			pointMemo = pointMemo + " " + point + " 충전" ;

			mjonPayVO.setPointMemo(pointMemo);
		
		return mjonPayVO;
	}
	
	public MjonPayVO setPayInfo(HttpServletRequest request, MjonPayVO mjonPayVO) throws Exception{
		
		if(!this.pgAuth(mjonPayVO , request)) {
			mjonPayVO.setPaySuccess(false);
			return mjonPayVO;
		}
		
		//세금 값 넣기
		mjonPayVO = this.setTexVO(mjonPayVO);
		//cash 값 넣기
		mjonPayVO = this.setCashVO(mjonPayVO);
		//point 값 넣기
		mjonPayVO = this.setPointVO(mjonPayVO);
		
		return mjonPayVO;
	}
}
