package cokr.xit.ens.modules.common.ctgy.intgrnbill.support;

import cokr.xit.ens.core.utils.CmmnUtil;
import org.springframework.http.*;
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.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Map;

public interface PayApi {

    /**
     * 결제 URL 생성정보 요청
     *
     * @param uri
     * @param mParam
     * @return
     */
    ResponseEntity<String> payUrl(String uri, Map<String, Object> mParam, HttpHeaders headers);

    /**
     * 결제정보 요청
     *
     * @param uri
     * @param mParam
     * @return
     */
    ResponseEntity<String> payNotice(String uri, Map<String, Object> mParam, HttpHeaders headers);

    /**
     * 납부가능여부
     *
     * @param uri
     * @param mParam
     * @return
     */
    ResponseEntity<String> payAble(String uri, Map<String, Object> mParam, HttpHeaders headers);

    /**
     * 납부결과
     *
     * @param uri
     * @param mParam
     * @return
     */
    ResponseEntity<String> payResult(String uri, Map<String, Object> mParam, HttpHeaders headers);

    /**
     * 결제취소
     *
     * @param uri
     * @param mParam
     * @return
     */
    ResponseEntity<String> payCancelResult(String uri, Map<String, Object> mParam, HttpHeaders headers);


    /**
     * API  호출
     *
     * @param method  호출메소드(GET/POST/PUT/DELETE)
     * @param url     호출 URL
     * @param body    파라미터
     * @param headers 요청헤더정보
     * @return
     * @author 박민규
     */
    default ResponseEntity<String> callApi(HttpMethod method, String url, String body, HttpHeaders headers) {
        return this.callApi(method, url, body, headers, 5000, 30000);
    }

    /**
     * API  호출
     *
     * @param method         호출메소드(GET/POST/PUT/DELETE)
     * @param url            호출 URL
     * @param body           파라미터
     * @param headers        요청헤더정보
     * @param connectTimeout 통신 연결 제한시간(ms)
     * @param readTimeout    응답데이터 read 제한시간(ms)
     * @return
     * @author 박민규
     */
    default ResponseEntity<String> callApi(HttpMethod method, String url, String body, HttpHeaders headers, int connectTimeout, int readTimeout) {
        StringBuffer sb = new StringBuffer();
        StringBuffer log = new StringBuffer();
        log.append(getClass().getSimpleName());
        ResponseEntity<String> responseEntity = null;
        try {
           
            HttpEntity<?> entity = null;
            UriComponents uri = null;
            switch (method) {
                case GET:
                    entity = new HttpEntity<>(headers);
                    uri = UriComponentsBuilder
                            .fromHttpUrl(String.format("%s?%s", url, body == null ? "" : body))
//							.encode(StandardCharsets.UTF_8)	//"%"기호가 "%25"로 인코딩 발생하여 주석처리 함.
                            .build(false);
                    break;
                case POST:
                    entity = new HttpEntity<>(body, headers);
                    uri = UriComponentsBuilder
                            .fromHttpUrl(url)
                            .encode(StandardCharsets.UTF_8)
                            .build();
                    break;

                default:
                    break;
            }

            sb.append("url => " + uri.toString())
                    .append("\n  method => " + method)
                    .append("\n  headers => " + entity.getHeaders().toString())
                    .append("\n  body => " + entity.getBody());

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

        } catch (HttpServerErrorException e) {
            responseEntity = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getStatusCode());
            log.append(System.getProperty("line.separator"))
                    .append("call API 서버오류")
                    .append("[ error ]: ")
                    .append(CmmnUtil.printStackTraceToString(e));
        } catch (HttpClientErrorException e) {
            responseEntity = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getStatusCode());
            log.append(System.getProperty("line.separator"))
                    .append("call API 클라이언트오류")
                    .append("[ error ]: ")
                    .append(CmmnUtil.printStackTraceToString(e));
        } catch (RestClientException e) {   
            responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.REQUEST_TIMEOUT);
            log.append(System.getProperty("line.separator"))
                    .append("RestAPI 호출 오류")
                    .append("[ error ]: ")
                    .append(CmmnUtil.printStackTraceToString(e));
        } catch (Exception e) {
            responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
            log.append(System.getProperty("line.separator"))
                    .append("call API 기타오류")
                    .append("[ error ]: ")
                    .append(CmmnUtil.printStackTraceToString(e));
        } finally {
            log.append(System.getProperty("line.separator"))
                    .append("[ REQUEST ]-----------------------------------------------------------------------")
                    .append(System.getProperty("line.separator"))
                    .append(sb.toString())
                    .append(System.getProperty("line.separator"))
                    .append("[ RESPONSE ]-----------------------------------------------------------------------")
                    .append(System.getProperty("line.separator"))
                    .append(responseEntity.getBody());
            System.out.println(log.toString());
        }

        return responseEntity;
    }
}
