package com.hp.ucmdb.rest.uiserver.integrationstudio.controllers.sample;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
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.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import javax.net.ssl.*;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
public class RestApiConnectionUtils {

    public static String loginServer(String serverIP, String userName, String password)throws JSONException, IOException{
        //HTTPS protocol, server IP and API type as the prefix of REST API URL.
        if(serverIP == null || serverIP.length() == 0 || userName == null || userName.length() == 0 || password == null || password.length()== 0){
            System.out.println( " please input correct serverIp or userName or password! " );
            return null;
        }
        String domainURLAndApiType= " https:// "  + serverIP +  " :8443/rest-api/ " ;

        //adminUser has the integration access.
        JSONObject loginJson = new JSONObject();
        loginJson.put( " clientContext " , " 1 " );
        loginJson.put( " username " ,userName);
        loginJson.put( " password " ,password);

        //Put username and password in HTTP request body and invoke REST API(rest-api/authenticate) with POST method to get token.
        System.out.print( " login server request :  " );
        String result = doPost(domainURLAndApiType+ " authenticate " , null, loginJson.toString());
        System.out.println( " the response of login is  "  + result);
        if(result == null || result.length() == 0){
            System.out.println( " Failed to connect with the UCMDB server! " );
            return result;
        }
        String token = new JSONObject(result).getString( " token " );

        if(token != null) System.out.println( " Connect to server Successfully! " );
        return token;
    }

    public static String getAllIntegrationPoints(String token, String serverIP)throws IOException{
        String domainURLAndApiType= " https:// "  + serverIP +  " :8443/rest-api/ " ;
        System.out.print( " getting all integration points request :  " );
        String allIntegrationPoints = doGet(domainURLAndApiType +  " integration/integrationpoints " , token);
        System.out.println(  " all integration points details :  "  + allIntegrationPoints);
        return allIntegrationPoints;
    }

    public static List getAllIntegrationPointNames(JSONObject allIntegrationPoints){
        List allIntegrationPointNames = new ArrayList<>();
        if (allIntegrationPoints != null) {
            Iterator iter = allIntegrationPoints.keys();
            while (iter.hasNext()) {
                Object integrationPoint = iter.next();
                allIntegrationPointNames.add((String)integrationPoint);
            }
        }
        return allIntegrationPointNames;
    }

    public static String getSingleIntegrationPoint(String token, String serverIP, String integrationPoint_name)throws IOException{
        String domainURLAndApiType= " https:// "  + serverIP +  " :8443/rest-api/ " ;
        System.out.print( " getting the  "  + integrationPoint_name +  "  integration point request :  " );
        return doGet(domainURLAndApiType +  " integration/integrationpoints/ "  + integrationPoint_name +  " ?detail=false " , token);
    }

    public static String activateOrDeactivateIntegrationPoint(String token, String serverIP, String integrationPoint_name, boolean enabled)throws IOException,JSONException,NoSuchAlgorithmException,KeyManagementException{
        String domainURLAndApiType= " https:// "  + serverIP +  " :8443/rest-api/ " ;
        JSONObject activeJson = new JSONObject();
//        activeJson.put( " name " , integrationPoint_name);
//        activeJson.put( " enabled " , enabled);// true: means active the integration point, false: means deactive it
        String activate = enabled ?  " activate "  :  " deactivate " ;
        System.out.print( activate +  "  integration point request :  " );
        return doPatch(domainURLAndApiType +  " integration/integrationpoints/ " + integrationPoint_name +  " ?enabled=true " , activeJson.toString(), token);
    }

    public static String syncJob(String token, String serverIP, String integrationPoint_name, String job_name, String operation_type)throws IOException,JSONException,NoSuchAlgorithmException,KeyManagementException{
        String domainURLAndApiType= " https:// "  + serverIP +  " :8443/rest-api/ " ;

        String job_id = integrationPoint_name +  " _ "  + job_name;
        JSONObject syncJson = new JSONObject();
        syncJson.put( " operationType " ,operation_type);//there are four values for the operation_type parameter: PUSH_FULL / PUSH_DELTA / POPULATION_FULL / POPULATION_DELTA */
        System.out.print( " sync job request :  " );
        return doPatch(domainURLAndApiType +  " integration/integrationpoints/ "  + integrationPoint_name +  " /jobs/ "  + job_name +  " ?operationtype= "  + operation_type, syncJson.toString(), token);
    }

    public static String testConnectionWithIntegration(String token, String serverIP, String integrationPoint_name)throws IOException{
        String domainURLAndApiType= " https:// "  + serverIP +  " :8443/rest-api/ " ;
        System.out.print( " test connection with integration point request :  " );
        return doGet(domainURLAndApiType +  " integration/integrationpoints/ "  + integrationPoint_name +  " /connectionstatus " , token);
    }


    public static String doPost(String url, String token, String content)throws IOException {
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader( " Content-Type " ,  " application/json;charset=utf-8 " );
        if(token != null) httpPost.setHeader( " Authorization " ,  " Bearer  "  + token);
        httpPost.setHeader( " Accept " ,  " application/json " );
        if(content!= null && content.length()>0){
            StringEntity entity = new StringEntity(content);
            httpPost.setEntity(entity);
        }

        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,
                (s, sslSession) -> true);

        CloseableHttpClient c = HttpClients
                .custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setSSLHostnameVerifier(new TrustAnyHostnameVerifier())
                .build();
        CloseableHttpResponse httpResponse = c.execute(httpPost);
        String result = EntityUtils.toString(httpResponse.getEntity());
        System.out.println( " POST call returned a status code of  "  + printStatusCode(httpResponse.getStatusLine().getStatusCode()));
        httpResponse.close();
        return result;
    }

    public static String doGet(String url, String token) throws  IOException {
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader( " Content-Type " ,  " application/json;charset=utf-8 " );
        httpGet.setHeader( " Authorization " ,  " Bearer  "  + token);
        httpGet.setHeader( " Accept " ,  " application/json " );

        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,
                (s, sslSession) -> true);

        CloseableHttpClient c = HttpClients
                .custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setSSLHostnameVerifier(new TrustAnyHostnameVerifier())
                .build();
        CloseableHttpResponse httpResponse = c.execute(httpGet);
        String result = EntityUtils.toString(httpResponse.getEntity());
        System.out.println( " GET call returned a status code of  "  + printStatusCode(httpResponse.getStatusLine().getStatusCode()));
        httpResponse.close();
        return result;
    }

    public static String doPatch(String url, String content, String token) throws IOException,NoSuchAlgorithmException, KeyManagementException {

        HttpPatch p = new HttpPatch(url);
        p.setHeader( " Content-Type " ,  " application/json;charset=utf-8 " );
        p.setHeader( " Authorization " ,  " Bearer  "  + token);
        p.setHeader( " Accept " ,  " application/json " );
        if(content!= null && content.length()>0){
            StringEntity entity = new StringEntity(content);
            p.setEntity(entity);
        }

        SSLContext sslcontext = null;
        try {
            sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
        } catch (NoSuchAlgorithmException | KeyManagementException | KeyStoreException e) {
            e.printStackTrace();
        }
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslcontext,
                (s, sslSession) -> true);

        CloseableHttpClient c = HttpClients
                .custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .setSSLHostnameVerifier(new TrustAnyHostnameVerifier())
                .build();
        CloseableHttpResponse httpResponse = c.execute(p);
        String result = EntityUtils.toString(httpResponse.getEntity());
        System.out.println( " PATCH call returned a status code of  "  + printStatusCode(httpResponse.getStatusLine().getStatusCode()));
        httpResponse.close();
        return result;
    }

    public static String printStatusCode(int status){
        String result =  " " ;
        switch (status){
            case 200:
                result =  " 200 (Successful) " ;break;
            case 400:
                result =  " 400 (Bad Request) Syntax/data provided is not valid for the request " ;break;
            case 401:
                result =  " 401 (Unauthorized) User not authorized or invalid session token " ;break;
            case 403:
                result =  " 403 (Forbidden) Operation is not allowed (for any user) " ;break;
            case 404:
                result =  " 404 (Not Found) The URI points to a non-existent resource/collection " ;break;
            case 405:
                result =  " 405 (Method Not Allowed) The HTTP method is not allowed for the resource " ;break;
            case 406:
                result =  " 406 (Not Acceptable) Media-type specified in the Accept header is not supported " ;break;
            case 412:
                result =  " 412 (Precondition Failed) Start and count values cannot be satisfied in a query " ;break;
            case 415:
                result =  " 415 (Unsupported Media Type) Media-type specified in the Content-Type header is not supported " ;break;
            case 500:
                result =  " 500 (Internal Server Error) An unexpected/server-side error has occurred " ;break;
            case 501:
                result =  " 501 (Not Implemented) The HTTP method is not currently implemented for the given resource/collection URI " ;break;
            case 503:
                result =  " 503 (Service Unavailable) The server is currently unavailable " ;break;

        }
        return result;
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }
}