package com.eactive.ext.kjb.sso;

import com.eactive.ext.kjb.common.KjbProperty;
import com.eactive.ext.kjb.common.KjbPropertyHolder;
import com.initech.eam.api.*;
import com.initech.eam.base.APIException;
import com.initech.eam.base.EmptyResultException;
import com.initech.eam.nls.CookieManager;
import com.initech.eam.smartenforcer.SECode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

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

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Vector;

@Slf4j
public class KjbSsoModule {
    private static volatile KjbSsoModule instance;

    private final Vector<String> PROVIDER_LIST = new Vector<String>();
    private final int COOKIE_SESSTION_TIME_OUT = 3000000;

    // 인증 타입 (ID/PW 방식 : 1, 인증서 : 3)
    private final String TOA = "1";
    private final String SSO_DOMAIN = ".kjbank.com";
    private final String COOKIE_PADDING = "_V42";

    private static final int timeout = 15000;

    private KjbSsoModule() {
        CookieManager.setEncStatus(true);
        SECode.setCookiePadding(COOKIE_PADDING);
    }

    public static KjbSsoModule getInstance() {
        if (instance == null) {
            synchronized (KjbSsoModule.class) {
                if (instance == null) {
                    instance = new KjbSsoModule();
                }
            }
        }
        return instance;
    }

    private static KjbProperty getProperty() {
        return KjbPropertyHolder.get();
    }

    private String getServiceName() {
        return getProperty().getSsoServiceName();
    }

    public String getAscpUrl() {
        KjbProperty prop = getProperty();
        return prop.getUrl() + prop.getSsoAscpUri();
    }

    private String getNlsUrl() {
        return "http://" + getProperty().getSsoDomain();
    }

    private String getNlsPort() {
        return String.valueOf(getProperty().getSsoNlsPort());
    }

    private String getNlsLoginUrl() {
        return getNlsUrl() + ":" + getNlsPort() + "/nls3/clientLogin.jsp";
    }

    private String getNlsLogoutUrl() {
        return getNlsUrl() + ":" + getNlsPort() + "/nls3/NCLogout.jsp";
    }

    private String getNlsErrorUrl() {
        return getNlsUrl() + ":" + getNlsPort() + "/nls3/error.jsp";
    }

    private String getNdUrl1() {
        return "http://" + getProperty().getSsoDomain() + ":5480";
    }

    public Vector<String> getProviderList() {
        Vector<String> list = new Vector<>();
        list.add(getProperty().getSsoDomain());
        return list;
    }
    
    
    @SuppressWarnings("unchecked")
	public NXContext getContext() {
		NXContext context = null;
		try {
			List<String> serverurlList = new ArrayList<>();
			serverurlList.add(getNdUrl1());
			context = new NXContext(serverurlList);
			CookieManager.setEncStatus(true);
			SECode.setCookiePadding(COOKIE_PADDING);
		}
		catch (Exception e)
		{
            log.warn("getContext", e);
		}
		return context;
	}


    /**
     * 통합 SSO ID 조회
     * @param request
     * @return
     */
    public String getSsoId(HttpServletRequest request) {
        String sso_id = null;
        sso_id = CookieManager.getCookieValue(SECode.USER_ID, request);
        return sso_id;
    }

    public String getSystemAccount(String sso_id) {
    	NXContext context = null;
        NXUserAPI userAPI = null;
        String retValue = null;

        try {
        	context = getContext();
            userAPI = new NXUserAPI(context);
            String serviceName = getServiceName();
            log.info("##############################################");
            log.info("sso_id 2: "+sso_id);
            log.info("SERVICE_NAME : "+ serviceName);
            log.info("##############################################");
            NXAccount account = userAPI.getUserAccount(sso_id, serviceName);
            log.info(account.toString());
            retValue = account.getAccountName();
            log.info("retValue = " + retValue);
        } catch (Exception e) {
            log.error("KjbSsoModule Exception", e);
        }
        return retValue;
    }

    /**
     * 통합 SSO 로그인페이지 이동
     * @param response
     * @param uurl
     * @throws Exception
     */
    public void goLoginPage(HttpServletResponse response, String uurl)
            throws Exception {
        CookieManager.addCookie(SECode.USER_URL, uurl, SSO_DOMAIN, response);
        CookieManager.addCookie(SECode.R_TOA, TOA, SSO_DOMAIN, response);
        response.sendRedirect(getNlsLoginUrl() + "?UURL=" + uurl);
    }

    /**
     * 통합 SSO 로그인페이지 이동
     * @param response
     * @throws Exception
     */
    public void goLoginPage(HttpServletResponse response) throws Exception {
        CookieManager.addCookie(SECode.USER_URL, getAscpUrl(), SSO_DOMAIN, response);
        CookieManager.addCookie(SECode.R_TOA, TOA, SSO_DOMAIN, response);
        response.sendRedirect(getNlsLoginUrl());
    }

    /**
     * 통합인증 세션을 체크 하기 위하여 사용되는 API
     * @param request
     * @param response
     * @return
     */
    public String getEamSessionCheck(HttpServletRequest request, HttpServletResponse response) {
        String retCode = "";
        try {
            retCode = CookieManager.verifyNexessCookie(request, response, 10, COOKIE_SESSTION_TIME_OUT, getProviderList());
        } catch(Exception npe) {
            log.warn("getEamSessionCheck", npe);
        }
        return retCode;
    }

    /**
     * ND API를 사용해서 쿠키검증하는것(현재 표준에서는 사용안함, 근데 해도 되기는 함)
     * @param request
     * @param response
     * @return
     */
    public String getEamSessionCheck2(HttpServletRequest request, HttpServletResponse response) {
        String retCode = "";
        try {
            NXContext ctx = getContext();
            NXNLSAPI nxNLSAPI = new NXNLSAPI(ctx);
            retCode = nxNLSAPI.readNexessCookie(request, response, 0, 0);
        } catch(Exception npe) {
            log.error("KjbSsoModule-getEamSessionCheck2 Exception", npe);
        }
        return retCode;
    }

    /**
     * SSO 에러페이지 URL
     * @param response
     * @param error_code
     * @throws Exception
     */
    public void goErrorPage(HttpServletResponse response, int error_code) throws Exception {
        CookieManager.removeNexessCookie(SSO_DOMAIN, response);
        CookieManager.addCookie(SECode.USER_URL, getAscpUrl(), SSO_DOMAIN, response);
        response.sendRedirect(getNlsErrorUrl() + "?errorCode=" + error_code);
    }

    /**
     *	사용자 기본정보 가져오기.
     *	@param	userid
     *	@return	Properties
     */
    public Properties getUserInfos(String userid) throws Exception {
    	NXContext context = null;
		context = getContext();
		
        NXUserAPI userAPI = new NXUserAPI(context);
        Properties propt = null;

        if (userid==null || userid.length() <= 0)
            return propt;

        try {
            NXUserInfo userInfo = userAPI.getUserInfo(userid);
            propt = new Properties();
            propt.setProperty("USERID", userInfo.getUserId());
            propt.setProperty("EMAIL", userInfo.getEmail());
            propt.setProperty("ENABLE", String.valueOf(userInfo.getEnable()));
            propt.setProperty("STARTVALID", userInfo.getStartValid());
            propt.setProperty("ENDVALID", userInfo.getEndValid());
            propt.setProperty("NAME", userInfo.getName());
            propt.setProperty("ENCPASSWD", userInfo.getEncpasswd());
            propt.setProperty("LASTPASSWDCHANGE", userInfo.getLastpasswdchange());
            propt.setProperty("LastLoginIP", userInfo.getLastLoginIp());
            propt.setProperty("LastLoginTime", userInfo.getLastLoginTime());
            propt.setProperty("LastLoginAuthLevel",	userInfo.getLastLoginAuthLevel());

        } catch (Exception e) {
            log.error("KjbSsoModule-getUserInfos Exception", e);
            throw e;
        }

        return propt;
    }

    /**
     * 사용자의 기본정보 중에서 입력된 키 값만 가지고 온다.
     * @param userid
     * @param key
     * @return
     * @throws Exception
     */
    public String getUserInfo(String userid, String key) throws Exception {
        if(userid==null|| userid.isEmpty()) return null;

        String userInfo = "";

        try {
            Properties propt = getUserInfos(userid);
            userInfo = propt.getProperty(key);
        } catch (Exception e) {
            log.error("KjbSsoModule-getUserInfos Exception", e);
            throw e;
        }
        return userInfo;
    }

    /**
     * 사용자 확장정보 조회
     * return : Properties
     * 사용자가 존재하지 않거나 확장필드가 없다면 return null
     */
    @SuppressWarnings("rawtypes")
    public Properties getUserExFields(String userid) throws Exception {
    	NXContext context = getContext();
        NXUserAPI userAPI = new NXUserAPI(context);
        Properties prop = null;
        NXExternalFieldSet nxefs = null;

        try {
            nxefs = userAPI.getUserExternalFields(userid);
            prop = new Properties();

            if (nxefs != null) {
                Iterator<?> iter = nxefs.iterator();
                while(iter.hasNext()) {
                    NXExternalField nxef = (NXExternalField) iter.next();
                    if(nxef.getName().equals("PASSINIT")){
                        String sPassintVal = (String) nxef.getValue();
                        prop.setProperty(nxef.getName(), sPassintVal.equals("") ? "0" : sPassintVal);
                    }
                    else
                        prop.setProperty(nxef.getName(), (String) nxef.getValue());
                    //System.out.println("확장 필드 " + nxef.getName() + " : " + nxef.getValue());
                }
            } else {
                // prop is null
                log.debug("KjbSsoModule-getUserExFields property is null");
            }
        } catch (EmptyResultException e) {
            // 사용자가 존재하지 않거나 확장필드가 없음
        	log.warn("사용자가 존재하지 않거나 확장필드가 없음", e);
        } catch (APIException e) {
        	log.warn("SSO-APIException", e);
            throw e;
            //e.printStackTrace();
        }
        //System.out.println("getUserExFields:[" + prop + "]");
        return prop;
    }

    /**
     * 사용자의 특정 확장 필드 정보 조회
     * return : String
     * 사용자가 존재하지 않거나 확장필드가 없다면 return null
     */
    public String getUserExField(String userid, String exName)
            throws Exception {
    	NXContext context = getContext();
        NXUserAPI userAPI = new NXUserAPI(context);
        NXExternalField nxef = null;
        String returnValue = null;

        try {
            log.debug("KjbSsoModule-getUserExField userid : {}", userid);
            nxef = userAPI.getUserExternalField(userid, exName);
            log.debug("KjbSsoModule-getUserExField nxef === {}", nxef.getValue());
            returnValue = (String) nxef.getValue();
        } catch (EmptyResultException e) {
            // 사용자가 존재하지 않거나 확장필드가 없음
        	log.warn("사용자가 존재하지 않거나 확장필드가 없음", e);
        } catch (Exception e) {
            log.error("KjbSsoModule-getUserExField Exception", e);
            throw e;
        }

        return returnValue;
    }
}
