
package cokr.xit.ens.core.utils;

import cokr.xit.ens.core.exception.code.EnsErrCd;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class CmmnUtil {

//	private final static Logger logger = LoggerFactory.getLogger(CmmnUtil.class);


    /**
     * <pre>메소드 설명: API 호출
     * 	-.반환결과
     * 	:result => 결과 코드(OK: 정상, others: 오류)
     * 	:resultMsg	=> 결과 메시지
     * 	:responseEntity => api 응답 메시지
     * </pre>
     *
     * @param method
     * @param url
     * @param param
     * @param headers
     * @return Map<String, Object> 요청처리 후 응답객체
     * @author: 박민규
     * @date: 2021. 8. 4.
     */
    public static Map<String, Object> callApi(HttpMethod method, String url, String param, HttpHeaders headers) {
        log.debug("param =======================");
        log.debug(param);


        Map<String, Object> resultMap = new HashMap<String, Object>();
        ResponseEntity<String> responseEntity = null;
        String result = EnsErrCd.OK.getCode();
        String resultMsg = EnsErrCd.OK.getCodeNm();

        try {
           
            HttpEntity<?> entity = null;
            UriComponents uri = null;
            switch (method) {
                case GET:
                    entity = new HttpEntity<>(headers);
                    uri = UriComponentsBuilder
                            .fromHttpUrl(String.format("%s?%s", url, param))
                            .encode()
                            .build();
                    break;
                case POST:
                    entity = new HttpEntity<>(param, headers);
                    uri = UriComponentsBuilder
                            .fromHttpUrl(url)
                            .encode()
                            .build();
                    break;

                default:
                    break;
            }


           
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            factory.setConnectTimeout(3000); 
            factory.setReadTimeout(3000);
            RestTemplate restTemplate = new RestTemplate(factory);
            responseEntity = restTemplate.exchange(uri.toString(), method, entity, String.class);  

           
//			코드: responseEntity.getStatusCodeValue()
//			메시지: responseEntity.getStatusCode()
        } catch (
                HttpServerErrorException e) {   
            result = EnsErrCd.ERR501.getCode();
            resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR501.getCodeNm(), e.getMessage());
            log.error(String.format("call API 서버오류[url =>%s param => %s error => %s]", url, param, e.getMessage()));
        } catch (
                HttpClientErrorException e) {   
            result = EnsErrCd.ERR502.getCode();
            resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR502.getCodeNm(), e.getMessage());
            log.error(String.format("call API 클라이언트오류[url =>%s param => %s error => %s]", url, param, e.getMessage()));
        } catch (RestClientException e) {   
            result = EnsErrCd.ERR503.getCode();
            resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR503.getCodeNm(), e.getMessage());
            log.error(String.format("RestAPI 호출 오류[url =>%s param => %s error => %s]", url, param, e.getMessage()));
        } catch (Exception e) {
            result = EnsErrCd.ERR999.getCode();
            resultMsg = String.format("%s [사유: %s]", EnsErrCd.ERR999.getCodeNm(), e.getMessage());
            log.error(String.format("call API 기타오류[url =>%s param => %s error => %s]", url, param, e.getMessage()));
        }


        
        resultMap.put("resCd", result);
        resultMap.put("resMsg", resultMsg);
        resultMap.put("responseEntity", responseEntity);
        return resultMap;
    }


    /**
     * <pre>메소드 설명: 객체를 Json 포맷 String으로 반환 한다.</pre>
     *
     * @param obj
     * @return String 요청처리 후 응답객체
     * @author: 박민규
     * @date: 2021. 8. 5.
     */
    public static String toJsonString(Object obj) {
        return toJsonString(obj, JsonInclude.Include.ALWAYS);
    }

    /**
     * <pre>메소드 설명: 객체를 Json 포맷 String으로 반환 한다.</pre>
     *
     * @param obj
     * @param type JsonInclude.Include
     *             <pre>
     *                                     [type 종류]
     *                                     	ALWAYS: 모든 필드
     *                                     	NON_NULL: null제외
     *                                      NON_ABSENT: null제외
     *                                      NON_EMPTY: null/absent/isEmpty()==true/lenth==0 제외
     *                                      NON_DEFAULT: empty는 제외된다.primitive 타입이 디폴트 값이면 제외한다. (int / Integer : 0 , boolean / Boolean : false 등)
     *                                     </pre>
     * @return String 요청처리 후 응답객체
     * @author: 박민규
     * @date: 2021. 8. 5.
     */
    public static String toJsonString(Object obj, JsonInclude.Include type) {
        String result = null;

        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.setSerializationInclusion(type);        
            result = mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
//			throw new CustomException(RESP_CODE.INTERNAL_SERVER_ERROR, String.format("obj -> jsonString converting fail:: %s", e.getMessage()));
            throw new RuntimeException(String.format("obj -> jsonString converting fail:: %s", e.getMessage()), e);
        }

        return result;
    }
//	/**
//	 * <pre>메소드 설명: jsonString을 Object로 반환한다</pre>
//	 * @param clz
//	 * @param jsonStr
//	 * @return Object 요청처리 후 응답객체
//	 * @author: 박민규
//	 * @date: 2021. 12. 23.
//	 */
//	public static Object jsonStringtoObj(Class clz, String jsonStr) {
//		Object result = null;
//
//		try {
//			ObjectMapper mapper = new ObjectMapper();
//			result = mapper.readValue(jsonStr, clz.getClass());
//		} catch (JsonProcessingException e) {
//			throw new RuntimeException(String.format("jsonString -> obj converting fail:: %s", e.getMessage()), e);
//		}
//
//		return result;
//	}

    public static boolean isEmpty(Object obj) {
        if (obj == null) return true;
        if ((obj instanceof String) && (((String) obj).trim().length() == 0)) {
            return true;
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }
        if (obj instanceof Map) {
            return ((Map<?, ?>) obj).isEmpty();
        }
        if (obj instanceof List) {
            return ((List<?>) obj).isEmpty();
        }
        if (obj instanceof Object[]) {
            return (((Object[]) obj).length == 0);
        }

        return false;
    }


    public static String getServerUrl() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

        return String.format("%s://%s:%s", request.getScheme(), request.getServerName(), request.getServerPort());
    }

    public static String printStackTraceToString(Exception e) {
        try {
            StringWriter errors = new StringWriter();
            e.printStackTrace(new PrintWriter(errors));

            return errors.toString();
        } catch (Exception ex) {
            return "printStackTrace 변환에 실패 했습니다. " + ex.getMessage();
        }
    }


}
