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

import cokr.xit.ens.core.utils.CmmnUtil;
import cokr.xit.ens.core.utils.IdGenerator;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * <ul>
 * <li>업무 그룹명: 카카오페이 내문서함 API 서비스</li>
 * <li>설 명: </li>
 * <li>작성일: 2021. 11. 18. 오후 5:01:36
 * </ul>
 *
 * @author 박민규
 */
@Slf4j
@Component
@Profile({"local-test"})
public class KkoMydocApiTest implements KkoMydocApiSpec {

    @Value("${contract.kakao.pay.mydoc.host}")
    private String HOST;
    @Value("${contract.kakao.pay.mydoc.api.send}")
    private String API_SEND;
    @Value("${contract.kakao.pay.mydoc.api.token}")
    private String API_TOKEN;
    @Value("${contract.kakao.pay.mydoc.api.readcompleted}")
    private String API_READCOMPLETED;
    @Value("${contract.kakao.pay.mydoc.api.status}")
    private String API_STATUS;
    @Value("${contract.kakao.pay.mydoc.api.bulksend}")
    private String API_BULKSEND;
    @Value("${contract.kakao.pay.mydoc.api.bulkstatus}")
    private String API_BULKSTATUS;

    /**
     * 모바일웹 연계 문서발송 요청
     * -.이용기관 서버에서 전자문서 서버로 문서발송 처리를 요청합니다.
     */
    @Override
    public ResponseEntity<String> send(String accessToken, String contractUuid, String jsonStr) {
       
        HttpHeaders headers = new HttpHeaders();
//		headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("Authorization", String.format("Bearer %s", accessToken));
        headers.set("Contract-Uuid", contractUuid);

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

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

        String uuid = IdGenerator.getShortUUID("BIN").substring(0, 40);
        String data = "{\"document_binder_uuid\":\"" + uuid + "\"}";
        return ResponseEntity.ok(data);
    }


    /**
     * 토큰 유효성 검증(Redirect URL  접속 허용/불허)
     */
    @Override
    public ResponseEntity<String> token(String accessToken, String documentBinderUuid, String token) {
       
        HttpHeaders headers = new HttpHeaders();
//		headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("Authorization", String.format("Bearer %s", accessToken));
        headers.set("X-Xit-DBUuid", documentBinderUuid);
        headers.set("X-Xit-Ott", token);

       
        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(API_TOKEN
                        .replace("{documentBinderUuid}", documentBinderUuid == null ? "" : documentBinderUuid)
                        .replace("{token}", token == null ? "" : token)
                );


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

        String data = "{\"token_status\":\"USED\",\"token_expires_at\":1624344762,\"token_used_at\":1624341176,\"doc_box_sent_at\":1624340817,\"doc_box_received_at\":1624340817,\"authenticated_at\":1624340958,\"user_notified_at\":1624340958,\"payload\":\"payload 파라미터 입니다.\"}";
        return ResponseEntity.ok(data);
    }


    /**
     * 문서 상태 변경 API
     * -.문서에 대해서 열람 상태로 변경. 사용자가 문서열람 시(OTT 검증 완료 후 페이지 로딩 완료 시점) 반드시 문서 열람 상태 변경 API를 호출해야 함.
     * -.미 호출 시 아래와 같은 문제 발생
     * 1)유통증명시스템을 사용하는 경우 해당 API를 호출한 시점으로 열람정보가 등록되어 미 호출 시 열람정보가 등록 되지 않음.
     * 2)문서상태조회 API(/v1/documents/{document_binder_uuid}/status) 호출 시 read_at최초 열람시간) 데이터가 내려가지 않음.
     */
    @Override
    public ResponseEntity<String> readCompleted(String accessToken, String documentBinderUuid) {
       
        HttpHeaders headers = new HttpHeaders();
//		headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("Authorization", String.format("Bearer %s", accessToken));
        headers.set("X-Xit-DBUuid", documentBinderUuid);

       
        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(API_READCOMPLETED.replace("{documentBinderUuid}", documentBinderUuid == null ? "" : documentBinderUuid));


       
        String jsonStr = "{                                 "
                + "    \"document\" :{               "
                + "        \"is_detail_read\" : true "
                + "    }                             "
                + "}                                 ";


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

        return new ResponseEntity<String>(HttpStatus.NO_CONTENT);

    }


    /**
     * 문서 상태 조회 API
     * -.이용기관 서버에서 카카오페이 전자문서 서버로 문서 상태에 대한 조회를 요청 합니다.
     * : 발송된 문서의 진행상태를 알고 싶은 경우, flow와 상관없이 요청 가능
     * : polling 방식으로 호출할 경우, 호출 간격은 5초를 권장.
     * -.doc_box_status 상태변경순서
     * : SENT(송신) > RECEIVED(수신) > READ(열람)/EXPIRED(미열람자료의 기한만료)
     */
    @Override
    public ResponseEntity<String> status(String accessToken, String contractUuid, String documentBinderUuid) {
       
        HttpHeaders headers = new HttpHeaders();
//		headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("Authorization", String.format("Bearer %s", accessToken));
        headers.set("Contract-Uuid", contractUuid);
        headers.set("X-Xit-DBUuid", documentBinderUuid);

       
        StringBuilder url = new StringBuilder();
        url.append(this.HOST)
                .append(API_STATUS.replace("{documentBinderUuid}", documentBinderUuid == null ? "" : documentBinderUuid));

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

        String data = "{\"doc_box_status\":\"READ\",\"doc_box_sent_at\":1616375652,\"doc_box_received_at\":1616375652,\"authenticated_at\":1616394336,\"token_used_at\":1616394336,\"doc_box_read_at\":1616397918,\"user_notified_at\":1616394336,\"payload\":\"payload 파라미터 입니다.\"}";
        return ResponseEntity.ok(data);

    }


    /**
     * 대량(bulk) 문서발송 요청
     * -.이용기관 서버에서 카카오페이 내문서함 서버로 대량(bulk) 문서발송 처리를 요청합니다.
     */
//	POST /v1/documents/bulk HTTP/1.1
//	Host: docs-gw.kakaopay.com (전용선/VPN 일 경우 docs-gw-gs.kakaopay.com) 
//	Content-Type: application/json;charset=UTF-8
//	Authorization: Bearer {Access_Token} 
//	Contract-Uuid: {Contract-Uuid}
    @Override
    public ResponseEntity<String> bulkSend(String accessToken, String contractUuid, String jsonStr) {
       
        HttpHeaders headers = new HttpHeaders();
//		headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("Authorization", String.format("Bearer %s", accessToken));
        headers.set("Contract-Uuid", contractUuid);

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

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

        String successDoc = "{\"external_document_uuid\":\"#{external_document_uuid}\",\"document_binder_uuid\":\"#{document_binder_uuid}\"},";

        Gson gson = new Gson();
        Map<String, List> m = gson.fromJson(jsonStr, Map.class);
        List<Map<String, Object>> documents = m.get("documents");
        StringBuffer data = new StringBuffer();
        data.append("{\"documents\":[");
        documents.stream()
                .map(document -> (Map<String, String>) document.get("property"))
                .forEach(property -> data.append(successDoc.replace("#{external_document_uuid}", property.get("external_document_uuid")).replace("#{document_binder_uuid}", IdGenerator.getShortUUID("BIN"))));
        data.append("]}");
        return ResponseEntity.ok(data.toString().replace(",]}", "]}"));

    }


    /**
     * 대량(bulk) 문서 상태 조회 API
     * -.이용기관 서버에서 카카오페이 전자문서 서버로 문서 상태에 대한 조회를 요청 합니다.
     * : 발송된 문서의 진행상태를 알고 싶은 경우, flow와 상관없이 요청 가능
     * : polling 방식으로 호출할 경우, 호출 간격은 5초를 권장.
     * -.doc_box_status 상태변경순서
     * : SENT(송신) > RECEIVED(수신) > READ(열람)/EXPIRED(미열람자료의 기한만료)
     */
//	POST /v1/documents/bulk/status HTTP/1.1
//	Host: docs-gw.kakaopay.com (전용선/VPN 일 경우 docs-gw-gs.kakaopay.com) 
//	Content-Type: application/json;charset=UTF-8
//	Authorization: Bearer {Access_Token} 
//	Contract-Uuid: {Contract-Uuid}
    @Override
    public ResponseEntity<String> bulkStatus(String accessToken, String contractUuid, String jsonStr) {
       
        HttpHeaders headers = new HttpHeaders();
//		headers.setContentType(MediaType.APPLICATION_JSON);
        headers.setContentType(new MediaType(MediaType.APPLICATION_JSON, Charset.forName("utf-8")));
        headers.set("Authorization", String.format("Bearer %s", accessToken));
        headers.set("Contract-Uuid", contractUuid);

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

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

        String successDoc = "{\"document_binder_uuid\":\"#{document_binder_uuid}\",\"status_data\":{\"doc_box_status\":\"RECEIVED\",\"doc_box_sent_at\":1499866132,\"doc_box_received_at\":1499866132,\"user_notified_at\":11223890}},";

        Gson gson = new Gson();
        Map<String, List> m = gson.fromJson(jsonStr, Map.class);
        List<String> documents = m.get("document_binder_uuids");
        StringBuffer data = new StringBuffer();
        data.append("{\"documents\":[");
        documents.stream()
                .forEach(documentBinderUuid -> data.append(successDoc.replace("#{document_binder_uuid}", documentBinderUuid)));
        data.append("]}");
        return ResponseEntity.ok(data.toString().replace(",]}", "]}"));
    }

    /**
     * <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 = ResponseEntity.ok("test");
        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))
                            .build(false);
                    break;
                case POST:
                    entity = new HttpEntity<>(body, headers);
                    uri = UriComponentsBuilder
                            .fromHttpUrl(url)
                            .encode(StandardCharsets.UTF_8)
                            .build();
                    break;

                default:
                    break;
            }

            sb.append("\n  url => " + uri.toString())
                    .append("\n  method => " + method)
                    .append("\n  headers => " + entity.getHeaders().toString())
                    .append("\n  body => " + entity.getBody());
        } catch (Exception e) {
            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;
    }

}

