package nlib.cmm;

import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.ui.ModelMap;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import nlib.bbs.web.BoardController;
import nlib.cmm.exception.ErrorMessage;
import nlib.restful.service.DataApiResVO;
import nlib.security.SecUserVO;
import nlib.user.service.LoginService;
import nlib.user.service.NlibLoginVO;
import nlib.util.StringUtil;

/**
 * <pre>
 * @Class Name : NlibCommonController.java
 * 
 * @Description : 컨트롤러의 공통적인 기능을 제공하는 컨트롤러 상위 클래스
 * 
 * 
 * @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
 *
 * </pre>
 *
 * @ ------------    --------    ---------------------------
 * @ 수정일                     수정자             수정내용
 * @ ------------    --------    ---------------------------
 * @ 2021. 7. 23.    KNKIM       최초 생성
 *
 * 
 * @author 이씨플라자 * DIGITALSHIP KNKIM
 * @since 2021. 7. 23.
 * @version 1.0
 *
 */
public class NlibCommonController {
	
	private static final Logger log = LoggerFactory.getLogger(BoardController.class);
	
	@Resource(name = "loginService")
	private LoginService _loginService;
	
	/**
	 * AuthKey 생성 시, 로그인하지 않은 사용자의 AuthKey 생성시 사용되는 접두어  
	 */
	static final String ANONYMOUS_AUTH_KEY_PREFIX = "GST-"; 

	private static final int INFO_ID_COUNCIL_CD = 1; /* 현재 지방문화원 코드를 지칭하는 식별자 */
	private static final int INFO_ID_COUNCIL_NM = 2; /* 현재 지방문화원 명칭을 지칭하는 식별자 */

	/**
	 * 스프링 시큐리티 Authentication를 통해서 사용자로그인정보 NlibLoginVO를 리턴한다.
	 *  
	 * @param authentication
	 * @return
	 */
	public NlibLoginVO getNlibLoginVO(Authentication authentication) {
		if(authentication == null) return new NlibLoginVO();
		
		return (NlibLoginVO)authentication.getPrincipal();
	}
	
	/**
	 * 스프링 시큐리티 Authentication를 통해서 사용자로그인정보 SecUserVO를 리턴한다.
	 * 
	 * @param authentication
	 * @return
	 */
	public SecUserVO getSecLoginVO(Authentication authentication) {
		
		if(authentication == null) return null;
		
		return (SecUserVO)authentication.getPrincipal();
	}
	
	/**
	 * 통합자료시스템 요청 시, 제공할 사용자정보 auth key 생성 
	 * - 로그인 한 경우 : 사용자ID를 BASE64로 인코딩한 값
	 * - 로그인하지 않은 경우 : GST-세션ID
	 * 
	 * @param request
	 * @param authentication
	 * @return
	 */
	public String createAuthKey(HttpServletRequest request, Authentication authentication) {
		
		String userId = null;
		String authKey = null;
		
		if(authentication != null) {
			userId = ((NlibLoginVO)authentication.getPrincipal()).getMbInfoId();
		}
		
		authKey = makeAuthKey(userId, request.getSession().getId());
		
		log.debug("createAuthKey > " + authKey);
		
		return authKey;
	}
	
	public static String makeAuthKey(String userId) {
		return makeAuthKey(userId, null);
	}
	public static String makeAuthKey(String userId, String sessionId) {
		
		if(nlib.util.StringUtil.isEmpty(userId)) {
			if(nlib.util.StringUtil.isNotEmpty(sessionId)) return ANONYMOUS_AUTH_KEY_PREFIX + sessionId;
			else return null;
		}
		
		return Base64.getEncoder().encodeToString(userId.getBytes());
	}
	
	public ResponseEntity<String> makeResponseEntityJson(DataApiResVO resVO) {

		// Convert Json
		ObjectMapper mapper = new ObjectMapper();
		String jsonStr = null;
		
		HttpHeaders headers = new HttpHeaders();
	    headers.add(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");
	    
		try {
			jsonStr = mapper.writeValueAsString(resVO);
			log.debug("RETURN DATA > json:" + jsonStr);
		} catch (JsonProcessingException e) {
			ErrorMessage eMsg = new ErrorMessage("ERR_JSON_CONVERT", "응답객체를 JSON으로 변환 처리 중 오류가 발생하였습니다. : " + e.toString());
			try { jsonStr = mapper.writeValueAsString(eMsg); } catch (JsonProcessingException ee) {}
			e.printStackTrace();
			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(jsonStr);
		}

	    return ResponseEntity.ok().headers(headers).body(jsonStr);
	}
	

	public ResponseEntity<String> makeResponseEntityJson(List<HashMap<String,String>> list) {

		// Convert Json
		ObjectMapper mapper = new ObjectMapper();
		String jsonStr = null;
		
		HttpHeaders headers = new HttpHeaders();
	    headers.add(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");
	    
		try {
			jsonStr = mapper.writeValueAsString(list);
			log.debug("RETURN DATA > json:" + jsonStr);
		} catch (JsonProcessingException e) {
			ErrorMessage eMsg = new ErrorMessage("ERR_JSON_CONVERT", "응답객체를 JSON으로 변환 처리 중 오류가 발생하였습니다. : " + e.toString());
			try { jsonStr = mapper.writeValueAsString(eMsg); } catch (JsonProcessingException ee) {}
			e.printStackTrace();
			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(jsonStr);
		}

	    return ResponseEntity.ok().headers(headers).body(jsonStr);
	}

	public ResponseEntity<String> makeResponseEntityJson(HashMap<String,Object> retMap) {

		// Convert Json
		ObjectMapper mapper = new ObjectMapper();
		String jsonStr = null;
		
		HttpHeaders headers = new HttpHeaders();
	    headers.add(HttpHeaders.CONTENT_TYPE, "application/json; charset=UTF-8");
	    
		try {
			jsonStr = mapper.writeValueAsString(retMap);
			log.debug("RETURN DATA > json:" + jsonStr);
		} catch (JsonProcessingException e) {
			ErrorMessage eMsg = new ErrorMessage("ERR_JSON_CONVERT", "응답객체를 JSON으로 변환 처리 중 오류가 발생하였습니다. : " + e.toString());
			try { jsonStr = mapper.writeValueAsString(eMsg); } catch (JsonProcessingException ee) {}
			e.printStackTrace();
			return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).headers(headers).body(jsonStr);
		}

	    return ResponseEntity.ok().headers(headers).body(jsonStr);
	}
	
	public ModelMap addParamsToModel(Map<String, String> paramMap, ModelMap model) {
		return addParamsToModel(paramMap, model, null, null);
	}
	public ModelMap addParamsToModel(Map<String, String> paramMap, ModelMap model, String upperMapName, String itemNames) {
		
		
		if(paramMap == null || paramMap.size() < 1) return model;
		if(model == null) return model;
		
		String filter = null;
		if(StringUtil.isNotEmpty(itemNames)) {
			filter = "," + itemNames + ",";
			filter = filter.replaceAll(" ", "");
		}
		
		boolean existUpperMap = StringUtil.isNotEmpty(upperMapName);
		Map<String, String> uppperMap = null;
		if(existUpperMap) uppperMap = new HashMap<String, String>();
		
		for(String key : paramMap.keySet()) {
			
			if(filter != null && !filter.contains("," + key + ",")) {
				continue;
			}
			if(existUpperMap) {
				uppperMap.put(key, paramMap.get(key));
			} else {
				model.addAttribute(key, paramMap.get(key));
			}
			
		}
		
		if(existUpperMap) model.addAttribute(upperMapName, uppperMap);
		
		return model;
	}
	
	
	public RedirectAttributes addParamsToRedirect(Map<String, String> paramMap, RedirectAttributes redirectAttrs) {
		return addParamsToRedirect(paramMap, redirectAttrs, null, null);
	}
	public RedirectAttributes addParamsToRedirect(Map<String, String> paramMap
			, RedirectAttributes redirectAttrs
			, String upperMapName
			, String itemNames) {
		
		
		if(paramMap == null || paramMap.size() < 1) return redirectAttrs;
		if(redirectAttrs == null) return redirectAttrs;
		
		String filter = null;
		if(StringUtil.isNotEmpty(itemNames)) {
			filter = "," + itemNames + ",";
			filter = filter.replaceAll(" ", "");
		}
		
		boolean existUpperMap = StringUtil.isNotEmpty(upperMapName);
		Map<String, String> uppperMap = null;
		if(existUpperMap) uppperMap = new HashMap<String, String>();
		
		for(String key : paramMap.keySet()) {
			
			if(filter != null && !filter.contains("," + key + ",")) {
				continue;
			}
			if(existUpperMap) {
				uppperMap.put(key, paramMap.get(key));
			} else {
				redirectAttrs.addFlashAttribute(key, paramMap.get(key));
			}
			
		}
		
		if(existUpperMap) redirectAttrs.addFlashAttribute(upperMapName, uppperMap);
		
		return redirectAttrs;
	}

	/**
	 * paramMap에 이전 요청에서 전달할 때 추가한 POST방식의 매개변수값을 paramMap에 추가한다.
	 *  
	 * @param paramMap
	 * @param req
	 */
	public void addParamFromInputFlash(Map<String, String> paramMap, HttpServletRequest req) {
		if(req == null) return;
		
		Map<String, String> inFlashMap = (Map<String, String>)RequestContextUtils.getInputFlashMap(req);
		if(inFlashMap == null || inFlashMap.size() < 1) return;
		
		if(paramMap == null) paramMap = new HashMap<String, String>();
		
		for(String key : inFlashMap.keySet()) {
			String value = inFlashMap.get(key);
			if(StringUtil.isNotEmpty(value)) {
				paramMap.put(key, value);
			}
		}
		
		return;
	}
	
	/**
	 * 현재 요청(또는 세션)하고 있는 지방문화원 코드를 리턴한다. 
	 *  
	 * @param request
	 * @return
	 */
	private String getCurCouncilInfo(HttpServletRequest request, int which) {

		HttpSession session = request.getSession();
		String councilInfo = (String)session.getAttribute( (which == INFO_ID_COUNCIL_CD ? "curCouncilCd" : "curCouncilNm"));
		if(StringUtil.isNotEmpty(councilInfo)) {
			return councilInfo;
		}
		
		// 지방문화원 코드 확인
		String curCouncilDnsHost = StringUtil.getHostName(request.getRequestURL().toString());
		HashMap<String, String> councilInfoMap = _loginService.selectCouncilInfoByDnsHost(curCouncilDnsHost);
		
		String curCouncilCd = councilInfoMap.get("councilCd");
		String curCouncilNm = councilInfoMap.get("councilNm");
		
		session.setAttribute("curCouncilNm", curCouncilNm);
		session.setAttribute("curCouncilCd", curCouncilCd);
		session.setAttribute("curCouncilDnsHost", curCouncilDnsHost);
		
		return which == INFO_ID_COUNCIL_CD ? curCouncilCd : curCouncilNm;
	}
	
	public String getCurCouncilCd(HttpServletRequest request) {
		return getCurCouncilInfo(request, INFO_ID_COUNCIL_CD);
	}
	
	public String getCurCouncilNm(HttpServletRequest request) {
		return getCurCouncilInfo(request, INFO_ID_COUNCIL_NM);
	}
	
}
