package com.icomsys.main_vm.biz.common.common.service;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.icomsys.main_vm.biz.advice.excep.CustomBadRequestException;
import com.icomsys.main_vm.biz.test.controller.testvo.APINodeVo;
import com.icomsys.main_vm.biz.test.controller.testvo.KeyValueVo;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.spi.json.JsonSmartJsonProvider;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;

import java.lang.reflect.Method;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class RestTemplateService {

    private final RestTemplate restTemplate;

    /**
     * @Name Get Api 호출 공통 모듈
     * @Description Get Call 공통화 모듈
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    public ResponseEntity<String> GetCall(UriComponents uri, HttpHeaders headers) {
        return restTemplate
                .exchange(uri.toUriString(), HttpMethod.GET, new HttpEntity<>(headers), String.class);
    }

    /**
     * @Name POST Api 호출 공통 모듈
     * @Description POST Api 호출 공통 모듈
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    public ResponseEntity<String> PostCall(UriComponents uri, HttpHeaders headers) {
        HttpEntity en = new HttpEntity<>(headers);
        return restTemplate
                .postForEntity(uri.toUriString(), en, String.class);
    }

    /**
     * @Name POST Api 호출 공통 모듈
     * @Description POST Api 호출 공통 모듈
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    public ResponseEntity<String> PostCall(UriComponents uri, HttpHeaders headers, String body) {
        HttpEntity en = new HttpEntity<>(body, headers);
        return restTemplate
                .postForEntity(uri.toUriString(), en, String.class);
    }

    /**
     * @Name API NODE
     * @Description API NODE 의기능 구현
     * init data로 통신후 response 요청값 리턴
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    public Map APINode(Map apiReqParam, Map serviceParam, String s) throws CustomBadRequestException, NoSuchMethodException {
        ResponseEntity res = null;
        APINodeVo vo = new Gson().fromJson(s, APINodeVo.class);
        HttpHeaders headers = ConvertHttpHeaders(vo.getHeader());
        UriComponents uriComponents = GetURI(vo.getParam(), apiReqParam, serviceParam, UriComponentsBuilder.newInstance().uri(CreateURI(vo.getURL(), apiReqParam, serviceParam)));
        if (vo.getUrlType().toUpperCase().equals(RequestMethod.GET.name())) {
            res = GetCall(uriComponents, headers);
        } else if (vo.getUrlType().toUpperCase().equals(RequestMethod.POST.name())) {
            if (vo.getBody() == null || vo.getBody().equals("")) {
                res = PostCall(uriComponents, headers);
            } else {
                String repBody = vo.getBody();
                log.info("post call using body - {}", repBody);
                repBody.replaceAll("/r", "");
                repBody.replaceAll("/n", "");
                log.info("post call using body - {}", repBody);

                for (Object e : apiReqParam.keySet()) {
                    if (repBody.contains(e.toString())) {
                        repBody.replaceAll("#\\{" + e.toString() + "}", apiReqParam.get(e).toString());
                        repBody.replaceAll("#\\[" + e.toString() + "]", apiReqParam.get(e).toString());
                    }
                }
                res = PostCall(uriComponents, headers, repBody);
            }
        } else {
            throw new NoSuchMethodException("MethodType Mismatch");
        }

        if (res.getStatusCodeValue() != 200) {
            throw new CustomBadRequestException("Network server error");
        }
        //기존 시나리오에 합쳐주는 로직 삭제
//        return APINodeResultMap(apiReqParam, responseJsonPath(vo.getResponse(), res.getBody()));
        //새 맵으로 리턴
        return responseJsonPath(vo.getResponse(), res.getBody());
    }

    /**
     * @Name API NODE용 메소드
     * @Description 요청값을 헤더로 컨버팅함.
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    private HttpHeaders ConvertHttpHeaders(List<KeyValueVo> dto) {
        HttpHeaders headers = new HttpHeaders();
        for (KeyValueVo e : dto) {
            headers.setContentType(new MediaType(MediaType.valueOf(e.getValue())));
        }
        return headers;
    }

    /**
     * @Name API NODE TEST 용 메소드 (사용안함)
     * @Description 요청값을 URI param으로 컨버팅함
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    private Map<String, String> ConvertParam(List<KeyValueVo> dto) {
        Map<String, String> paramMap = new HashMap<>();
        for (KeyValueVo e : dto) {
            paramMap.put("#{" + e.getValue() + "}", e.getDesc());
        }
        return paramMap;
    }

    private URI CreateURI(String uri, Map apiReqParam, Map serviceParam) {
        for (Object e : apiReqParam.keySet()) {
            if (uri.contains(e.toString())) {
                uri.replaceAll(e.toString(), apiReqParam.get(e).toString());
            }
        }
        for (Object e : serviceParam.keySet()) {
            if (uri.contains(e.toString())) {
                uri.replaceAll(e.toString(), serviceParam.get(e).toString());
            }
        }
        return URI.create(uri);
    }

    /**
     * @Name API NODE용 메소드
     * @Description 요청값을 URI 로 완성시킴
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    private UriComponents GetURI(List<KeyValueVo> dto, Map<String, String> apiReqParam, Map<String, String> serviceParam, UriComponentsBuilder builder) {
        for (KeyValueVo e : dto) {
            if (apiReqParam.containsKey(e.getValue())) {
                builder.queryParam(e.getKey(), apiReqParam.get(e.getValue()));
            } else {
                builder.queryParam(e.getKey(), e.getValue());
            }
            if (serviceParam.containsKey(e.getValue())) {
                builder.queryParam(e.getKey(), serviceParam.get(e.getValue()));
            } else {
                builder.queryParam(e.getKey(), e.getValue());
            }
        }
        log.info("uri - {}", builder.build().toUriString());
        return builder.build();
    }

    /**
     * @Name API NODE용 메소드
     * @Description Call 완료값을 갖고 요청값을 찾아 리턴함.
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    private Map responseJsonPath(List<KeyValueVo> dto, Object body) {
        Map result = new HashMap();
        for (KeyValueVo e : dto) {
            String[] key = e.getValue().toString().split("\\.");
            result.put(key[key.length - 1], (Object) JsonPath.read(new JsonSmartJsonProvider().parse(body.toString()), e.getValue()));
        }
        return result;
    }

    /**
     * @Name API NODE용 메소드
     * @Description 결과값을 맵타입으로 컨버팅함
     * @Author JangWonSeok
     * @CreateDate 2023. 03. 14.
     */
    private Map APINodeResultMap(Map origin, Map jsonPath) {
        for (Object e : jsonPath.keySet()) {
            origin.put(e, jsonPath.get(e));
        }
        return origin;
    }

}
