// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package ai.vespa.metricsproxy.service;

import ai.vespa.util.http.hc5.VespaHttpClientBuilder;

import java.util.logging.Level;
import com.yahoo.yolean.Exceptions;
import org.apache.hc.client5.http.classic.methods.HttpGet;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.BasicHttpClientResponseHandler;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.core5.util.Timeout;

import java.io.IOException;
import java.net.URI;
import java.util.logging.Logger;

/**
 * HTTP client to get metrics or health data from a service
 *
 * @author hmusum
 * @author bjorncs
 */
public abstract class HttpMetricFetcher {

    private final static Logger log = Logger.getLogger(HttpMetricFetcher.class.getPackage().getName());
    public final static String STATE_PATH = "/state/v1/";
    // The call to apache will do 3 retries. As long as we check the services in series, we can't have this too high.
    public static int CONNECTION_TIMEOUT = 5000;
    private final static int SOCKET_TIMEOUT = 60000;
    private final URI url;
    protected final VespaService service;
    private static final CloseableHttpClient httpClient = createHttpClient();


    /**
     * @param service the service to fetch metrics from
     * @param port    the port to use
     */
    HttpMetricFetcher(VespaService service, int port, String path) {
        this.service = service;

        String u = "http://localhost:" + port + path;
        this.url = URI.create(u);
        log.log(Level.FINE, "Fetching metrics from " + u + " with timeout " + CONNECTION_TIMEOUT);
    }

    String getJson() throws IOException {
        log.log(Level.FINE, "Connecting to url " + url + " for service '" + service + "'");
        return httpClient.execute(new HttpGet(url), new BasicHttpClientResponseHandler());
    }

    public String toString() {
        return this.getClass().getSimpleName() + " using " + url;
    }

    String errMsgNoResponse(IOException e) {
        return "Unable to get response from service '" + service + "': " +
                Exceptions.toMessageString(e);
    }

    void handleException(Exception e, String data, int timesFetched) {
        logMessage("Unable to parse json '" + data + "' for service '" + service + "': " +
                           Exceptions.toMessageString(e), timesFetched);
    }

    private void logMessage(String message, int timesFetched) {
        if (service.isAlive() && timesFetched > 5) {
            log.log(Level.INFO, message);
        } else {
            log.log(Level.FINE, message);
        }
    }

    void logMessageNoResponse(String message, int timesFetched) {
        if (timesFetched > 5) {
            log.log(Level.WARNING, message);
        } else {
            log.log(Level.INFO, message);
        }
    }

    private static CloseableHttpClient createHttpClient() {
        return VespaHttpClientBuilder.create()
                .setUserAgent("metrics-proxy-http-client")
                .setDefaultRequestConfig(RequestConfig.custom()
                                                 .setConnectTimeout(Timeout.ofMilliseconds(CONNECTION_TIMEOUT))
                                                 .setResponseTimeout(Timeout.ofMilliseconds(SOCKET_TIMEOUT))
                                                 .build())
                .build();
    }

}

@@ -177,24 +177,29 @@
 tp.hc5.Vespa
+Async
 HttpClientBu
@@ -206,16 +206,100 @@
 ilder;%0A%0A
+import java.util.concurrent.ExecutionException;%0Aimport java.util.concurrent.Future;%0A
 import j
@@ -322,16 +322,17 @@
 .Level;%0A
+%0A
 import c
@@ -393,22 +393,20 @@
 t5.http.
-classi
+asyn
 c.method
@@ -407,22 +407,32 @@
 methods.
-HttpGe
+SimpleHttpReques
 t;%0Aimpor
@@ -464,28 +464,40 @@
 ttp.
-config.RequestConfig
+async.methods.SimpleHttpResponse
 ;%0Aim
@@ -532,51 +532,28 @@
 ttp.
-impl.classic.BasicHttpClientResponseHandler
+config.RequestConfig
 ;%0Aim
@@ -593,14 +593,12 @@
 mpl.
-classi
+asyn
 c.Cl
@@ -604,24 +604,29 @@
 loseableHttp
+Async
 Client;%0Aimpo
@@ -1382,24 +1382,29 @@
 loseableHttp
+Async
 Client httpC
@@ -1432,17 +1432,16 @@
 ent();%0A%0A
-%0A
     /**%0A
@@ -1984,90 +1984,317 @@
     
-return httpClient.execute(new HttpGet(url), new BasicHttpClientResponseHandler());
+Future%3CSimpleHttpResponse%3E response = httpClient.execute(new SimpleHttpRequest(%22GET%22, url), null);%0A        try %7B%0A            return response.get().getBodyText();%0A        %7D catch (InterruptedException %7C ExecutionException e) %7B%0A            throw new IOException(%22Failed fetching '%22 + url + %22': %22 + e);%0A        %7D
 %0A   
@@ -3299,24 +3299,29 @@
 loseableHttp
+Async
 Client creat
@@ -3348,20 +3348,53 @@
     
-return
+CloseableHttpAsyncClient client = 
  Vespa
+Async
 Http
@@ -3841,21 +3841,68 @@
   .build();%0A
+        client.start();%0A        return client;%0A
     %7D%0A%0A%7D%0A

Use async http the simple way.