package org.jenkinsci.plugins.jenkernetes.workflowsteps;

import com.google.common.net.HttpHeaders;
import com.google.gson.Gson;
import com.google.gson.JsonIOException;
import com.google.gson.JsonSyntaxException;

import groovy.json.JsonBuilder;
import groovy.json.JsonSlurper;

import org.apache.http.HttpHost;
import org.apache.http.client.ClientProtocolException;
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.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;

import javax.net.ssl.SSLContext;

/**
 * TODO: Insert description here. (generated by elibixby)
 */
public class KubernetesClient {

	private static final class BearerToken {
		public String BearerToken;
		@SuppressWarnings("unused")
		public boolean Insecure;
	}
	
	private static final String BEARER_TOKEN_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/token";

	private static final CloseableHttpClient CLIENT;
	private static final HttpHost HOST;

	static {
		SSLContextBuilder builder = SSLContexts.custom();
		try {
			builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeyStoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		SSLContext sslContext = null;
		try {
			sslContext = builder.build();
		} catch (KeyManagementException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext,
				SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

		Collection<BasicHeader> headers = new ArrayList<BasicHeader>();
		headers.add(new BasicHeader(HttpHeaders.CONTENT_TYPE, "application/json"));

		String bearerToken = null;
		try {
			bearerToken = (new Gson()).fromJson(new FileReader(new File(BEARER_TOKEN_PATH)), BearerToken.class).BearerToken;
		} catch (JsonSyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (JsonIOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		headers.add(new BasicHeader(HttpHeaders.AUTHORIZATION, "Bearer " + bearerToken));

		CLIENT = HttpClients.custom()
				.setDefaultHeaders(headers)
				.setSSLSocketFactory(sslsf).build();
		
		InetAddress kubernetesAddr = null;
		try {
		  kubernetesAddr = InetAddress.getByName("kubernetes");
		} catch (UnknownHostException e) {
		  e.printStackTrace();
		}
		HOST = new HttpHost(kubernetesAddr, 443, "https");
	}

	//version string
	//TODO Add namespace support
	private static final String PREFIX = "/api/v1/namespaces/default/";

	private static Object parse(CloseableHttpResponse resp) throws IOException{
		try{
			return (new JsonSlurper()).parse((new InputStreamReader(resp.getEntity().getContent())));
		} finally{
			resp.close();
		}
	}

	private static StringEntity toEntity(Object payload) throws UnsupportedEncodingException{
		return new StringEntity(new JsonBuilder(payload).toString());
	}

	private static <T extends HttpRequestBase> CloseableHttpResponse makeCall(T request) 
			throws ClientProtocolException, IOException {
		return CLIENT.execute(HOST, request);
	}

    public static Object get(String path) 
			throws ClientProtocolException, 
			IOException {
		return parse(makeCall(new HttpGet(PREFIX.concat(path))));
	}

	public static Object delete(String path) 
			throws ClientProtocolException,
			IOException{  
		return parse(makeCall(new HttpDelete(PREFIX.concat(path))));
	}

	public static Object create(String path, Object payload) 
			throws ClientProtocolException,
			IOException{
		HttpPost post = new HttpPost(PREFIX.concat(path));
		post.setEntity(toEntity(payload));    
		return parse(makeCall(post));
	}

	public static Object update(String path, Object payload) 
			throws ClientProtocolException,
			IOException{

		HttpPut put = new HttpPut(PREFIX.concat(path));
		put.setEntity(toEntity(payload));
		return parse(makeCall(put));
	}
}