package cokr.xit.ens.modules.kkoalimtalk.service.support;

import cokr.xit.ens.core.utils.CmmnUtil;
import cokr.xit.ens.modules.kkoalimtalk.domain.SendDetailKkoAlimtalk;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
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.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
public class KkoAlimtalkApi {

    @Value("${contract.kakao.alimtalk.biztalk.host}")
    private String HOST;
    @Value("${contract.kakao.alimtalk.biztalk.token.expire}")
    private String TOKEN_EXPIRE;
    @Value("${contract.kakao.alimtalk.biztalk.api.token}")
    private String API_TOKEN;
    @Value("${contract.kakao.alimtalk.biztalk.api.send-batch}")
    private String API_SEND_BATCH;
    @Value("${contract.kakao.alimtalk.biztalk.api.get-result-all}")
    private String API_GET_RESULT_ALL;
    @Value("${contract.kakao.alimtalk.biztalk.api.get-result-poll}")
    private String API_GET_RESULT_POLL;
    @Value("${contract.kakao.alimtalk.biztalk.api.ack-result-poll}")
    private String API_ACK_RESULT_POLL;

    /**
     * 사용자토큰요청
     *
     * @return
     */
    public ResponseEntity<String> token(String bsId, String passwd) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));


        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(this.API_TOKEN);


        Map<String, Object> mParam = new HashMap<String, Object>();
        mParam.put("bsid", bsId);
        mParam.put("passwd", passwd);
        mParam.put("expire", Long.parseLong(this.TOKEN_EXPIRE));
        String jsonStr = CmmnUtil.toJsonString(mParam);


        ResponseEntity<String> resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers);
        return resp;
    }

    /**
     * 사용자토큰요청 테스트
     *
     * @return
     */
    public ResponseEntity<String> tokenTest() {
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        Map<String, Object> mResp = new HashMap<>();
        mResp.put("responseCode", "1000");
        mResp.put("msg", null);
        mResp.put("token", "eyJhbGciOiJIUzI1NiJ9.eyJic2lkIjoid2lsc29uX25iZ21zXzIiLCJleHAiOjE1NjY5NzQ3NTksImlhdCI6MTU2Njg4ODM1OSwiaXBBZGRyIjoiMTcyLjE2LjAuNCJ9.moG5MwvbG7uJHAmG_4THEzup9QT50jf0sBEmkf07698");


        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        String result = null;
        try {
            result = gson.toJson(mResp);
        } catch (Exception e) {
            e.printStackTrace();
        }


        ResponseEntity<String> resp = new ResponseEntity<String>(result, HttpStatus.OK);
        return resp;
    }

    /**
     * 알림톡배치전송요청
     * -.1회 최대 500건
     *
     * @param btToken
     * @param jsonStr
     * @return
     */
    public ResponseEntity<String> sendBatch(String btToken, String jsonStr) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("bt-token", btToken);


        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(this.API_SEND_BATCH);


        ResponseEntity<String> resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers);
        return resp;
    }

    /**
     * 사용자토큰요청 테스트
     *
     * @return
     */
    public ResponseEntity<String> sendBatchTest(List<SendDetailKkoAlimtalk> list) {
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        List<Map<String, String>> msgList = list.stream()
                .map(row -> {
                    Map<String, String> msg = new HashMap<>();
                    msg.put("msgIdx", row.getMsgIdx());
                    msg.put("responseCode", "1000");
                    return msg;
                })
                .collect(Collectors.toList());
        Map<String, Object> mResp = new HashMap<>();
        mResp.put("responseCode", "1000");
        mResp.put("msg", "Successfully received. Call /v2/kko/getResultAll to see the result");
        mResp.put("msgList", msgList);


        Gson gson = new GsonBuilder().disableHtmlEscaping().create();
        String result = null;
        try {
            result = gson.toJson(mResp);
        } catch (Exception e) {
            e.printStackTrace();
        }


        ResponseEntity<String> resp = new ResponseEntity<String>(result, HttpStatus.OK);
        return resp;
    }

    /**
     * 전송결과처리
     *
     * @param btToken
     * @return
     */
    public ResponseEntity<String> getResultAll(String btToken) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("bt-token", btToken);


        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(this.API_GET_RESULT_ALL);


        ResponseEntity<String> resp = this.callApi(HttpMethod.GET, url.toString(), null, headers);
        return resp;
    }

    /**
     * 전송결과 Polling
     *
     * @param btToken
     * @return
     */
    public ResponseEntity<String> getResultPoll(String btToken) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("bt-token", btToken);


        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(this.API_GET_RESULT_POLL);


        ResponseEntity<String> resp = this.callApi(HttpMethod.GET, url.toString(), null, headers);
        return resp;
    }

    /**
     * 전송결과 Polling 승인처리
     *
     * @param btToken
     * @param pk
     * @return
     */
    public ResponseEntity<String> ackResultPoll(String btToken, String pk) {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("bt-token", btToken);


        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(this.API_ACK_RESULT_POLL);


        Map<String, String> mParam = new HashMap<String, String>();
        mParam.put("pk", pk);
        String jsonStr = CmmnUtil.toJsonString(mParam);


        ResponseEntity<String> resp = this.callApi(HttpMethod.POST, url.toString(), jsonStr, headers);
        return resp;
    }


    /**
     * <pre>메소드 설명: API 호출
     * </pre>
     *
     * @param method
     * @param url
     * @param body
     * @param headers
     * @return ResponseEntity 요청처리 후 응답객체
     * @author: 박민규
     * @date: 2021. 8. 4.
     * @apiNote: 사이트 참조 https://e2e2e2.tistory.com/15
     */
    private ResponseEntity<String> callApi(HttpMethod method, String url, String body, HttpHeaders headers) {

        StringBuffer sb = new StringBuffer();
        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;
            }



            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            factory.setConnectTimeout(3000);
//            factory.setReadTimeout(3000);
            factory.setReadTimeout(10000);
            RestTemplate restTemplate = new RestTemplate(factory);
            sb.append("\n  url => " + uri.toString())
                    .append("\n  method => " + method)
                    .append("\n  headers => " + entity.getHeaders().toString())
                    .append("\n  body => " + entity.getBody());
            responseEntity = restTemplate.exchange(URI.create(uri.toString()), method, entity, String.class);

            /*
             * HttpStatus 정보 확인 방법
             * 	-.코드: responseEntity.getStatusCodeValue()
             * 	-.메시지: responseEntity.getStatusCode()
             */

        } catch (HttpServerErrorException e) {
            responseEntity = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getStatusCode());
            log.error("call API 서버오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e));
        } catch (HttpClientErrorException e) {
            responseEntity = new ResponseEntity<String>(e.getResponseBodyAsString(), e.getStatusCode());
            log.error("call API 클라이언트오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e));
        } catch (RestClientException e) {
            responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.REQUEST_TIMEOUT);
            log.error("RestAPI 호출 오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e));
        } catch (Exception e) {
            responseEntity = new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
            log.error("call API 기타오류\n[ url ]: {} \n[ param ]: {} \n[ error ]: {}", url, body, CmmnUtil.printStackTraceToString(e));
        } finally {
            log.info("카카오 알림톡 API\n[ REQUEST ]-----------------------------------------------------------------------\n{}\n[ RESPONSE ]-----------------------------------------------------------------------\n{}", sb.toString(), responseEntity.getBody());
        }


        return responseEntity;
    }


}
