package incheon.ags.por.util;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.egovframe.rte.fdl.cmmn.EgovAbstractServiceImpl;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.springframework.stereotype.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import incheon.ags.por.mapper.PorFileUtilsMapper;
import incheon.ags.por.vo.PorRtmsVO;
import lombok.RequiredArgsConstructor;

/**
 * 임시 데이터 조회용
 */
@Component("porConnectUtils")
@RequiredArgsConstructor
public class PorConnectUtils extends EgovAbstractServiceImpl {
	private static final HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build();

	public JSONArray estate(PorRtmsVO porRtmsVO) throws Exception {
		String estateUrl = "https://imap.incheon.go.kr/icgisapi/getEstate.jsp";
		estateUrl += "?type=" + "rtms";
		estateUrl += "&dealtype=" + porRtmsVO.getDealType();
		estateUrl += "&bldtype=" + porRtmsVO.getBldType();
		estateUrl += "&lawd_cd=" + porRtmsVO.getLawdCd();
		estateUrl += "&dealymdtype=" + porRtmsVO.getDealYmdType();
		estateUrl += "&deal_y=" + porRtmsVO.getDealY();
		
		if(("q").equals(porRtmsVO.getDealYmdType())){
			estateUrl += "&deal_q=" + porRtmsVO.getDealQ();
		}else if(("p").equals(porRtmsVO.getDealYmdType())) {
			estateUrl += "&deal_m=" + porRtmsVO.getDealP();
		}
		System.out.println("estateUrl : " + estateUrl);
		URL url = new URL(estateUrl);
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("GET");
		connection.setRequestProperty("Content-Type", "application/json");
		connection.setDoOutput(true);
		connection.setDoInput(true);
		
		connection.setConnectTimeout(10_000);
		connection.setReadTimeout(30_000);
		
		connection.connect();
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
		StringBuilder response = new StringBuilder();
		String line;
		while ((line = reader.readLine()) != null) {
			response.append(line);
		}
		reader.close();
		
		JSONParser parse = new JSONParser();
		JSONArray obj = (JSONArray) parse.parse(response.toString());
		
		return obj;
		
	}
	
	public JSONObject kras(Map<String, String> paramMap) throws Exception {
		System.out.println("run : " + paramMap.get("url") + paramMap.get("param"));
		URL url = new URL(paramMap.get("url") + paramMap.get("param"));
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("GET");
		connection.setRequestProperty("Content-Type", "application/json");
		
		connection.setDoOutput(true);
		connection.setDoInput(true);
		
		connection.setConnectTimeout(10_000);
		connection.setReadTimeout(30_000);
		
		connection.connect();
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
		StringBuilder response = new StringBuilder();
		String line;
		while ((line = reader.readLine()) != null) {
			response.append(line);
		}
		reader.close();
		
		System.out.println("close : " + paramMap.get("url") + paramMap.get("param"));
		
		JSONParser parse = new JSONParser();
		// System.out.println(paramMap.get("url") + paramMap.get("param") + "\\n" + response.toString());
		JSONObject obj = new JSONObject();
		try {
			obj = (JSONObject) parse.parse(response.toString());
		}catch (Exception e) {
			// TODO: handle exception
			obj.put("TotalCount", 0);
		}
		
		return obj;
	}
	
	public String korep(Map<String, String> paramMap) throws Exception {
		URL url = new URL(paramMap.get("url") + paramMap.get("param"));
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		connection.setRequestMethod("GET");
		connection.setRequestProperty("Content-Type", "application/xml");
		
		connection.setDoOutput(true);
		connection.setDoInput(true);
		
		connection.setConnectTimeout(10_000);
		connection.setReadTimeout(30_000);
		
		connection.connect();
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
		StringBuilder response = new StringBuilder();
		String line;
		while ((line = reader.readLine()) != null) {
			response.append(line);
		}
		reader.close();
		
		String text = response.toString();
		if(text == null || text.length() <= 0) {
			return "";
		}
		String xml = xmlToString(text);
		
		return xml;
	}
	
	public JSONObject ssl(Map<String, String> paramMap) throws Exception {
		System.out.println("run ssl : " + paramMap.get("url") + paramMap.get("param"));
		
		TrustManager[] trustAllCerts = { new X509TrustManager() {
			public X509Certificate[] getAcceptedIssuers() {
				return new X509Certificate[0];
			}
			public void checkServerTrusted(X509Certificate[] arg0, String arg1)
					throws CertificateException {
			}
			public void checkClientTrusted(X509Certificate[] arg0, String arg1)
					throws CertificateException {
			}
		}};

		SSLContext sc = SSLContext.getInstance("TLS");
		HostnameVerifier hv = new HostnameVerifier() {
			public boolean verify(String arg0, SSLSession arg1) {
				return true;
			}
		};
		sc.init(null, trustAllCerts,  new SecureRandom());
		
		URL url = new URL(paramMap.get("url") + paramMap.get("param"));
		HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
		connection.setSSLSocketFactory(sc.getSocketFactory());
		connection.setHostnameVerifier((h, s) -> true);
		connection.setRequestMethod("GET");
		
		connection.setRequestProperty("Accept", "application/json");
		connection.setRequestProperty("User-Agent", "Mozilla/5.0");
		
		connection.setDoOutput(false);
		
		connection.setConnectTimeout(10_000);
		connection.setReadTimeout(30_000);
		
		int code = connection.getResponseCode();
		InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
		
		connection.connect();
		// BufferedReader reader = null;
		StringBuilder response = new StringBuilder();
		/*
		 * while ((line = reader.readLine()) != null) { response.append(line); }
		 */
		
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, java.nio.charset.StandardCharsets.UTF_8))) {
		    String line;
		    while ((line = reader.readLine()) != null) response.append(line);
		}
		
		
		System.out.println("close ssl : " + paramMap.get("url") + paramMap.get("param"));
		
		JSONParser parse = new JSONParser();
		// System.out.println(paramMap.get("url") + paramMap.get("param") + "\\n" + response.toString());
		JSONObject obj = new JSONObject();
		try {
			obj = (JSONObject) parse.parse(response.toString());
		}catch (Exception e) {
			// TODO: handle exception
			obj.put("TotalCount", 0);
		}
		
		return obj;
	}
	
	public JSONObject sslTest(Map<String, String> paramMap) throws Exception {
		System.out.println("run ssl : " + paramMap.get("url") + paramMap.get("param"));
		
		TrustManager[] trustAllCerts = { new X509TrustManager() {
			public X509Certificate[] getAcceptedIssuers() {
				return new X509Certificate[0];
			}
			public void checkServerTrusted(X509Certificate[] arg0, String arg1)
					throws CertificateException {
			}
			public void checkClientTrusted(X509Certificate[] arg0, String arg1)
					throws CertificateException {
			}
		}};
		
		SSLContext sc = SSLContext.getInstance(paramMap.get("protocol"));
		HostnameVerifier hv = new HostnameVerifier() {
			public boolean verify(String arg0, SSLSession arg1) {
				return true;
			}
		};
		sc.init(null, trustAllCerts,  new SecureRandom());
		
		URL url = new URL(paramMap.get("url") + paramMap.get("param"));
		HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
		connection.setSSLSocketFactory(sc.getSocketFactory());
		connection.setHostnameVerifier((h, s) -> true);
		connection.setRequestMethod(paramMap.get("method"));
		
		if(paramMap.get("accept") != null && !("").equals(paramMap.get("accept"))) {
		    connection.setRequestProperty("Accept", paramMap.get("accept"));
		}
		if(paramMap.get("contentType") != null && !("").equals(paramMap.get("contentType"))) {
		    connection.setRequestProperty("Content-type", paramMap.get("contentType"));
		}
		connection.setRequestProperty("User-Agent", "Mozilla/5.0");
		
		connection.setDoOutput(false);
		
		connection.setConnectTimeout(10_000);
		connection.setReadTimeout(30_000);
		
		int code = connection.getResponseCode();
		InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
		
		connection.connect();
		// BufferedReader reader = null;
		StringBuilder response = new StringBuilder();
		/*
		 * while ((line = reader.readLine()) != null) { response.append(line); }
		 */
		
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, java.nio.charset.StandardCharsets.UTF_8))) {
			String line;
			while ((line = reader.readLine()) != null) response.append(line);
		}
		
		
		System.out.println("close ssl : " + response.toString());
		
		JSONParser parse = new JSONParser();
		// System.out.println(paramMap.get("url") + paramMap.get("param") + "\\n" + response.toString());
		JSONObject obj = new JSONObject();
		try {
			obj = (JSONObject) parse.parse(response.toString());
		}catch (Exception e) {
			// TODO: handle exception
			obj.put("TotalCount", 0);
		}
		
		return obj;
	}
	
	public String klisSoap(Map<String, String> paramMap) throws Exception {
		String url = paramMap.get("url");
		// String url = "http://10.188.140.232:6333/ows/services/Klis?wsdl";
//		String url = "http://10.10.232.13:8180/SoapSample/services/Brokerage";
		
		String soapRequest = paramMap.get("soapRequest");
		
		HttpResponse<String> response = null;
		
		try {
			System.out.println("soap url : " + url);
			System.out.println("soap soapRequest : " + soapRequest);
			HttpRequest request = HttpRequest.newBuilder()
				    .uri(URI.create(url))
				    .timeout(Duration.ofSeconds(30))
				    .header("Content-Type", "text/xml;charset=UTF-8")
				    .header("SOAPAction", "\"\"")
				    .header("Accept-Charset", "UTF-8")
				    .POST(HttpRequest.BodyPublishers.ofString(soapRequest, StandardCharsets.UTF_8))
				    .build();
			response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
		}catch (Exception e) {
			// TODO: handle exception
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
			Document doc = dBuilder.newDocument();
			
			Element rootElement = doc.createElement("Response");
			doc.appendChild(rootElement);
			
			Element error = doc.createElement("error");
			error.appendChild(doc.createTextNode(e.getLocalizedMessage() + " : " + e.getMessage()));
			rootElement.appendChild(error);
			
			Element code = doc.createElement("code");
			code.appendChild(doc.createTextNode("500"));
			rootElement.appendChild(code);
			
			Transformer tf = TransformerFactory.newInstance().newTransformer();
			tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
			tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
			tf.setOutputProperty(OutputKeys.INDENT, "yes");
			
			StringWriter sw = new StringWriter();
			tf.transform(new DOMSource(doc), new StreamResult(sw));
			
			return sw.toString();
		}
		
		if(response != null) {
			return response.body();
		}else {
			return "error : response is null";
		}
		// return response.body();
	}
	
	private String xmlToString(String str) {
		StringBuilder sb = new StringBuilder();
		char ch;
		int len = str.length();
		for (int i = 0; i < len; i++) {
			ch = str.charAt(i);
			if (ch == '\\' && str.charAt(i + 1) == 'u') {
				sb.append((char) Integer.parseInt(str.substring(i + 2, i + 6), 16));
				i += 5;
				continue;
			}
			sb.append(ch);
		}
		return sb.toString();
	}
	
	public String makeCacheKey(String prefix, String p1, String p2, String p3, String p4, String p5){
		return prefix + "|" + String.valueOf(p1) + "|" + String.valueOf(p2) + "|" + String.valueOf(p3)
				+ "|" + String.valueOf(p4) + "|" + String.valueOf(p5);
	}


	public JSONArray sliceRows(JSONArray allRows, int page, int perPage){
	    JSONArray sliced = new JSONArray();
	    if(allRows == null) return sliced;

	    int start = (page - 1) * perPage;
	    int end = start + perPage;

	    if(start < 0) start = 0;
	    if(end > allRows.size()) end = allRows.size();
	    if(start >= allRows.size()) return sliced;

	    for(int i=start;i<end;i++){
	        sliced.add(allRows.get(i));
	    }
	    return sliced;
	}

	public JSONArray mergeRows(JSONArray target, JSONArray part){
	    if(target == null) target = new JSONArray();
	    if(part == null) return target;
	    
	    for(int i=0;i<part.size();i++){
	        target.add(part.get(i));
	    }
	    return target;
	}

	
} 