package incheon.res.rdm.com.levy;


import incheon.res.rdm.com.levy.vo.LevyNextBodyVO;
import incheon.res.rdm.com.levy.vo.LevyNextHeadVO;
import incheon.res.rdm.com.levy.vo.LevyNextOutputVO;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;

import java.util.HashMap;
import java.util.Map;

import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.RestClientException;
import org.springframework.web.client.RestTemplate;


import javax.annotation.PostConstruct;
import javax.net.ssl.*;

@Component("LevyNextUtil")
public class LevyNextUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(LevyNextUtil.class);
	
    private static final int CONNECT_TIMEOUT = 3000;
    private static final int READ_TIMEOUT = 30000;

	@Value("${levy.ip}")
	private String CALL_URL;
	@Value("${levy.port}")
	private String PORT;

	@Autowired private ObjectMapper objectMapper;
	private RestTemplate restTemplate;
	private String baseUrl;


	@PostConstruct
	public void init() throws Exception {

		this.baseUrl = String.format("https://%s:%s%s", CALL_URL, PORT, "/mediate/ltis");
		this.restTemplate = createRestTemplate();
		LOGGER.error(":::::LevyNextUtil 연동 URL 초기화: {}", baseUrl);
	}


	/**
	 * SSL 인증서 검증을 제어할 수 있는 RestTemplate 생성
	 */
	private RestTemplate createRestTemplate() throws Exception  {

		// 인증서 신뢰하는 SSLContext 생성
		SSLContext sslContext = SSLContextBuilder.create()
				.loadTrustMaterial((chain, authType) -> true)
				.build();

		// 특정 IP만 허용
		SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(
				sslContext,
				new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"},  // 모든 TLS 버전 허용
				null,  // 모든 Cipher Suite 허용 (약한 알고리즘 포함)
				(hostname, session) -> {
					boolean isAllowed = hostname.equals(CALL_URL);
					if (!isAllowed) {
						LOGGER.error(":::::LevyNextUtil 허용되지 않은 호스트 접근 시도: {}", hostname);
					}
					return isAllowed;
				}
		);

		// HttpClient 생성
		CloseableHttpClient httpClient = HttpClients.custom()
				.setSSLSocketFactory(socketFactory)
				.build();

		// RequestFactory 설정
		HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
		factory.setConnectTimeout(CONNECT_TIMEOUT);
		factory.setReadTimeout(READ_TIMEOUT);

		RestTemplate template = new RestTemplate(factory);

		return template;
	}


	public LevyNextOutputVO callLevyNext(LevyNextBodyVO bodyVo, LevyNextHeadVO headVo) {
		try {
			String jsonRequest = buildRequestJson(bodyVo, headVo);
			LOGGER.error(":::::LevyNextUtil buildRequestJson 요청 JSON: {}", jsonRequest);

			HttpHeaders headers = buildHeaders(headVo, bodyVo);
			HttpEntity<String> requestEntity = new HttpEntity<>(jsonRequest, headers);

			ResponseEntity<String> response = restTemplate.exchange(
					baseUrl,
					HttpMethod.POST,
					requestEntity,
					String.class
			);

			LOGGER.error(":::::LevyNextUtil response getStatusCode: {}", response.getStatusCode());

			return parseResponse(response.getBody());

		} catch (RestClientException e) {
			LOGGER.error(":::::LevyNextUtil callLevyNext 호출 중 네트워크 오류 발생", e);
			return createErrorResponse("네트워크 오류", e.getMessage());
		} catch (Exception e) {
			LOGGER.error(":::::LevyNextUtil callLevyNext 호출 중 오류 발생", e);
			return createErrorResponse("오류", e.getMessage());
		}
	}

	/**
	 * 요청 JSON 생성
	 */
	private String buildRequestJson(LevyNextBodyVO bodyVo, LevyNextHeadVO headVo) throws Exception {
		Map<String, Object> request = new HashMap<>();
		Map<String, Object> body = new HashMap<>();

		body.put("reqVo", bodyVo);
		request.put("header", headVo);
		request.put("body", body);

		return objectMapper.writeValueAsString(request);
	}

	/**
	 * HTTP 헤더 생성
	 */
	private HttpHeaders buildHeaders(LevyNextHeadVO headVo, LevyNextBodyVO bodyVo) {
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.APPLICATION_JSON);
		headers.set("Accept-Charset", "UTF-8");
		headers.set("IF_ID", headVo.getIfId());
		headers.set("SRC_ORG_CD", bodyVo.getSgbCd());
		headers.set("SRC_SYS_CD", "RES");

		return headers;
	}

	/**
	 * 응답 JSON 파싱
	 */
	private LevyNextOutputVO parseResponse(String jsonResponse) {
		try {
			LOGGER.error(":::::LevyNextUtil parseResponse 응답 JSON: {}", jsonResponse);

			JsonNode rootNode = objectMapper.readTree(jsonResponse);
			JsonNode bodyNode = rootNode.get("body");
			if (bodyNode == null) {
				return createErrorResponse("오류", "body 노드 없음");
			}

			JsonNode resVoNode = bodyNode.get("resVo");
			if (resVoNode == null) {
				return createErrorResponse("오류", "resVo 노드 없음");
			}

			String linkRstCd = resVoNode.path("linkRstCd").asText();
			String linkRstMsg = resVoNode.path("linkRstMsg").asText();
			if (!"000".equals(linkRstCd)) {
				LOGGER.error(":::::LevyNextUtil parseResponse linkRstCd 오류: {} - {}", linkRstCd, linkRstMsg);
				return createErrorResponse("오류", "linkRstCd 값이 000이 아님");
			}

			LevyNextOutputVO outputVo = objectMapper.treeToValue(resVoNode, LevyNextOutputVO.class);
			LOGGER.error(":::::LevyNextUtil parseResponse 응답 처리 완료: {}", outputVo);

			return outputVo;

		} catch (Exception e) {
			LOGGER.error(":::::LevyNextUtil parseResponse 응답 JSON 파싱 중 오류 발생", e);
			return createErrorResponse("오류", e.getMessage());
		}
	}

	/**
	 * 오류 응답 객체 생성
	 */
	private LevyNextOutputVO createErrorResponse(String errorType, String errorMessage) {
		LevyNextOutputVO errorVo = new LevyNextOutputVO();
		errorVo.setLinkRstMsg(String.format("%s: %s", errorType, errorMessage));
		return errorVo;
	}

}
