package com.sfnt.ldk.util;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class ServiceUtil {
	private static final Log log = LogFactory.getLog(ServiceUtil.class);
	private static final String HEADER_ORIGIN = "Origin";
	private static final String ORIGIN_VALUE = "http://127.0.0.1";
	private static final String HEADER_CONTENT_TYPE = "Content-Type";
	private static final String CONTENT_TYPE_VALUE = "application/json";
	private static final String HEADER_ACCEPT = "Accept";
	private static final String DEFAULT_JSON_CONTENT_TYPE = "application/json";
	
	private ServiceUtil() {
		throw new IllegalStateException("ServiceUtil class");
	}

	public static CloseableHttpClient createHttpClient(String url) {
		CloseableHttpClient httpClient = null;
		if (url.indexOf("https") != -1) {
			try {
				httpClient = HttpClients.custom().setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
						.setSSLContext(new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
							public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
								return true;
							}
						}).build()).build();
			} catch (Exception e) {
				log.error("Exception in creating http client instance", e);
			}
		} else {
			httpClient = HttpClients.createDefault();
		}

		return httpClient;
	}

	public static HttpGet createHttpGet(int timeOut, String url, Map<String, String> headers) {
		HttpGet httpGet = new HttpGet(url);
		httpGet.setHeader(HEADER_ORIGIN, ORIGIN_VALUE);
		httpGet.setHeader(HEADER_ACCEPT, DEFAULT_JSON_CONTENT_TYPE);
		httpGet.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_VALUE);
		
		if(!headers.isEmpty()) {
			Set<String> key = headers.keySet();
			for (String header:key) {
				httpGet.setHeader(header, headers.get(header));
			}
		}

		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeOut)
				.setConnectionRequestTimeout(timeOut).setSocketTimeout(timeOut).build();

		httpGet.setConfig(requestConfig);

		return httpGet;
	}

	public static HttpPatch createHttpPatch(int timeOut, String url, String requestBody, Map<String, String> headers) {
		HttpPatch httpPatch = new HttpPatch(url);
		httpPatch.setHeader(HEADER_ORIGIN, ORIGIN_VALUE);
		httpPatch.setHeader(HEADER_ACCEPT, DEFAULT_JSON_CONTENT_TYPE);
		httpPatch.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_VALUE);
		
		if(!headers.isEmpty()) {
			Set<String> key = headers.keySet();
			for (String header:key) {
				httpPatch.setHeader(header, headers.get(header));
			}
		}

		StringEntity paramEntity = new StringEntity(requestBody, StandardCharsets.UTF_8);
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeOut)
				.setConnectionRequestTimeout(timeOut).setSocketTimeout(timeOut).build();

		httpPatch.setConfig(requestConfig);
		httpPatch.setEntity(paramEntity);

		return httpPatch;
	}

	public static HttpDelete createHttpDelete(int timeOut, String url, Map<String, String> headers) {
		HttpDelete httpDelete = new HttpDelete(url);
		httpDelete.setHeader(HEADER_ORIGIN, ORIGIN_VALUE);
		httpDelete.setHeader(HEADER_ACCEPT, DEFAULT_JSON_CONTENT_TYPE);
		httpDelete.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_VALUE);

		if(!headers.isEmpty()) {
			Set<String> key = headers.keySet();
			for (String header:key) {
				httpDelete.setHeader(header, headers.get(header));
			}
		}

		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeOut)
				.setConnectionRequestTimeout(timeOut).setSocketTimeout(timeOut).build();

		httpDelete.setConfig(requestConfig);

		return httpDelete;
	}

	public static HttpPost createHttpPost(int timeOut, String url, String requestBody, Map<String, String> headers) {
		HttpPost httpPost = new HttpPost(url);
		httpPost.setHeader(HEADER_ORIGIN, ORIGIN_VALUE);
		httpPost.setHeader(HEADER_ACCEPT, DEFAULT_JSON_CONTENT_TYPE);
		httpPost.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_VALUE);
		
		if(!headers.isEmpty()) {
			Set<String> key = headers.keySet();
			for (String header:key) {
				httpPost.setHeader(header, headers.get(header));
			}
		}

		StringEntity paramEntity = new StringEntity(requestBody, StandardCharsets.UTF_8);
		RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(timeOut)
				.setConnectionRequestTimeout(timeOut).setSocketTimeout(timeOut).build();

		httpPost.setConfig(requestConfig);
		httpPost.setEntity(paramEntity);

		return httpPost;
	}

	public static void closeHttpClient(CloseableHttpClient httpClient, CloseableHttpResponse response) {
		if (response != null) {
			try {
				response.close();
			} catch (IOException e) {
				log.error("Error while closing response : ", e);
			}
		}
		if (httpClient != null) {
			try {
				httpClient.close();
			} catch (IOException e) {
				log.error("Error while closing httpClient : ", e);
			}
		}
	}

	public static InputStream getInputStream(String fileName) {
		return ServiceUtil.class.getClassLoader().getResourceAsStream(fileName);
	}

	public static String getDataFromResponse(HttpResponse response) throws Exception {
		String responseXml = EntityUtils.toString(response.getEntity());
		EntityUtils.consume(response.getEntity());
		return responseXml;
	}
}
