package com.conveyal.taui.controllers;

import com.conveyal.r5.analyst.error.TaskError;
import com.conveyal.r5.common.JsonUtilities;
import com.conveyal.taui.util.HttpUtil;
import com.conveyal.taui.AnalystConfig;
import com.google.common.io.ByteStreams;
import com.sun.tools.javac.util.List;
import org.apache.http.ExceptionLogger;
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.conn.HttpHostConnectException;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spark.Request;
import spark.Response;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;

import static spark.Spark.*;

/**
 * Handles talking to the broker.
 */
public class SinglePointAnalysisController {
    public static final Logger LOG = LoggerFactory.getLogger(SinglePointAnalysisController.class);

    public static byte[] analysis (Request req, Response res) throws IOException {
        // we already know the user is authenticated, and we need not check if they have access to the graphs etc,
        // as they're all coded with UUIDs which contain significantly more entropy than any human's account password.
        String path = req.pathInfo().replaceAll("^/api/analysis/", "");
        String method = req.requestMethod();

        String brokerUrl = AnalystConfig.offline ? "http://localhost:6001" : AnalystConfig.brokerUrl;

        CloseableHttpResponse brokerRes = null;

        try {
            if ("GET".equals(method)) {
                HttpGet get = new HttpGet(brokerUrl + "/" + path);
                brokerRes = HttpUtil.httpClient.execute(get);
            } else if ("POST".equals(method)) {
                HttpPost post = new HttpPost(brokerUrl + "/" + path);
                post.setEntity(new StringEntity(req.body(), ContentType.create(req.contentType(), "UTF-8")));
                brokerRes = HttpUtil.httpClient.execute(post);
            } else if ("DELETE".equals(method)) {
                HttpDelete delete = new HttpDelete(brokerUrl + "/" + path);
                brokerRes = HttpUtil.httpClient.execute(delete);
            } else {
                throw new RuntimeException("Unsupported HTTP method on request, not proxying to the broker.");
            }
            res.status(brokerRes.getStatusLine().getStatusCode());
            res.type(brokerRes.getFirstHeader("Content-Type").getValue());
            // TODO set encoding?
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            InputStream is = new BufferedInputStream(brokerRes.getEntity().getContent());
            try {
                long l = ByteStreams.copy(is, baos);
                LOG.info("Returning {} bytes to scenario editor frontend", l);
                is.close();
                EntityUtils.consume(brokerRes.getEntity());
            } catch (IOException e) {
                reportException(res, e);
            }
            return baos.toByteArray();
        } catch (IOException e) {
            reportException(res, e);
        } finally {
            if (brokerRes != null) brokerRes.close();
        }
        return null;
    }

    public static void reportException (Response response, Exception exception) {
        LOG.error("Uncaught exception: ", exception.toString());
        exception.printStackTrace();
        response.status(500);
        response.type("text/json");
        List<TaskError> taskErrors = List.of(new TaskError(exception));
        response.body(new String(JsonUtilities.objectToJsonBytes(taskErrors)));
    }

    public static void register () {
        // TODO is there a way to do a wildcard that includes slashes?
        // Also, are there any broker endpoints that don't have two path components.
        post("/api/analysis/*/*", SinglePointAnalysisController::analysis);
        get("/api/analysis/*/*", SinglePointAnalysisController::analysis);
        delete("/api/analysis/*/*", SinglePointAnalysisController::analysis);
    }
}

@@ -251,86 +251,8 @@
 ms;%0A
-import com.sun.tools.javac.util.List;%0Aimport org.apache.http.ExceptionLogger;%0A
 impo
@@ -308,16 +308,16 @@
 sponse;%0A
+
 import o
@@ -457,62 +457,8 @@
 st;%0A
-import org.apache.http.conn.HttpHostConnectException;%0A
 impo
@@ -830,66 +830,41 @@
 ava.
-net.SocketTimeoutException;%0Aimport java.nio.charset.Charse
+util.Arrays;%0Aimport java.util.Lis
 t;%0A%0A
@@ -3658,15 +3658,21 @@
 s = 
+Arrays.as
 List
-.of
 (new

fix incorrect import, use Arrays.asList(), addresses #33