package nlib.restful.service.impl;

import java.nio.charset.StandardCharsets;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;

import nlib.restful.service.DataApiInterface;
import nlib.restful.service.DataApiReqVO;
import nlib.restful.service.DataApiResVO;
import nlib.util.StringUtil;

/**
 * <pre>
 * @Class Name : DataApiRESTful.java
 * 
 * @Description : 통합자료관리시스템에 RESTful API를 통해 질의/응답을 처리한다.
 * 
 * 
 * @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
 *
 * </pre>
 *
 * @ ------------    --------    ---------------------------
 * @ 수정일                     수정자             수정내용
 * @ ------------    --------    ---------------------------
 * @ 2021. 6. 22.    KNKIM       최초 생성
 *
 * 
 * @author 이씨플라자 * DIGITALSHIP KNKIM
 * @since 2021. 6. 22.
 * @version 1.0
 *
 */
public class DataApiRESTful implements DataApiInterface {

	private static final Logger log = LoggerFactory.getLogger(DataApiRESTful.class);
	
	/* DataApi 접속 서버 정보 */ 
	@Value("#{properties['dataapi.server.ip']}") 
	private String DAPI_SERVER_IP;
	
	@Value("#{properties['dataapi.server.port']}") 
	private String DAPI_SERVER_PORT;
	
	@Value("#{properties['dataapi.server.protocol']}") 
	private String DAPI_SERVER_PROTOCOL;
	
	/**
	 * 실제 RESTful API 서버로 요청을 전송하고, 응답받은 자료를 응답VO에 담아서 리턴한다.
	 * 
	 * @param reqVO
	 * @param method
	 * @return
	 */
	public DataApiResVO request(DataApiReqVO reqVO) {
		
		log.debug("request > " + reqVO.getReqMethod());
	
    	DataApiResVO resVO = null;
    	
    	try {

        	//-----------------------------------
    		// 입력값 검증작업 
        	//-----------------------------------
    		resVO = DataApiInterface.checkReqCommonParams(reqVO);
        	if(resVO != null) return resVO;
        	HttpMethod method = reqVO.getReqMethod();
    	
        	//-----------------------------------
        	// 폼 파라메터 생성 작업 및 요청 처리 
        	//-----------------------------------
    		String url = DAPI_SERVER_PROTOCOL + "://" + DAPI_SERVER_IP + ("80".equals(DAPI_SERVER_PORT) ? "" : ":" + DAPI_SERVER_PORT) + reqVO.getReqUrl();
    		log.debug("REQ URL : " + url);

    		HttpHeaders headers = new HttpHeaders();
    		headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    		
    		ResponseEntity<String> responseEntity = null;
    		RestTemplate restTemplate = new RestTemplate();
    		restTemplate.getMessageConverters()
    			.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
    		
    		HttpStatus statusCode = HttpStatus.OK;
    		String resultXML = null;
    				
    		if(method == HttpMethod.GET) {
        		HttpEntity requestEntity = new HttpEntity(headers);
        		try {
	        		responseEntity = restTemplate.exchange (DataApiInterface.makeRequestParamUrl(url, reqVO), method, requestEntity, String.class);
	        		statusCode = responseEntity.getStatusCode();
	        		resultXML = responseEntity.getBody();
        		} catch(HttpClientErrorException e) {
        			//e.printStackTrace();
        			resultXML = e.getResponseBodyAsString();
        			statusCode = e.getStatusCode();
        		} catch(HttpServerErrorException e) {
        			//e.printStackTrace();
        			resultXML = e.getResponseBodyAsString();
        			statusCode = e.getStatusCode();
        		}
    		} else if(method == HttpMethod.POST) {
        		MultiValueMap<String, String> parameters = DataApiInterface.makeRequestParamMultiValueMap(reqVO); 
        		parameters.forEach((k, v) -> log.debug("params > " + k + " : " + v));
        		HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity(parameters, headers);
        		try {
        			responseEntity = restTemplate.postForEntity(url, requestEntity , String.class);
        			statusCode = responseEntity.getStatusCode();
        			resultXML = responseEntity.getBody();
        		} catch(HttpClientErrorException e) {
        			e.printStackTrace();
        			resultXML = e.getResponseBodyAsString();
        			statusCode = e.getStatusCode();
        		} catch(HttpServerErrorException e) {
        			e.printStackTrace();
        			resultXML = e.getResponseBodyAsString();
        			statusCode = e.getStatusCode();
        		}
    		} else {
    			String message = "RESTFul API Http Method 설정 오류입니다. : POST, GET 방식만 허용됩니다.";
    			log.error("request > " + message);
        		return DataApiInterface.makeErrorRes("E_ERR_METHOD", message);
    		}
    		
        	//-----------------------------------
        	// 응답 처리  
        	//-----------------------------------
    		log.debug("RES StatusCode : " + statusCode);
    	    log.debug("RES resultXML : " + resultXML);
    	    
    	    // 응답 자료 객체화 
    		resVO = DataApiInterface.convertXmlToResVO(resultXML);
    		
    		// 처리결과 코드 확인 
    		if(StringUtil.isEmpty(resVO.getResultCode())) {
    			String resultMessage = resVO.getResultMessage();
        	    if (statusCode == HttpStatus.OK) {
        	    	resVO.setResultCode("S_HTTP_STATUS_OK");
        	    	resVO.setResultMessage(StringUtil.isEmpty(resultMessage) ? "정상처리되었습니다." : resultMessage);
        	    } else {
        	    	resVO.setResultCode("E_STATUS_CODE_FAIL");
        	    	resVO.setResultMessage(StringUtil.isEmpty(resultMessage) ? String.format("처리에 실패하였습니다. (HTTP상태코드 : %s)", statusCode.toString()) : resultMessage);
        	    }
    		}
    		
    		log.debug("RES resVO : resultCode    = " + resVO.getResultCode());
    		log.debug("RES resVO : resultMessage = " + resVO.getResultMessage());
    		
    	} catch(Exception e) {
    		e.printStackTrace();
    		log.error("request > Exception 발생 : " + e.toString());
    		return DataApiInterface.makeErrorRes("E_REQ_EXCEPTION", e.toString());
    	}
    	
	    return resVO;	
	}


}
