package marketing.heyday.hartmann.fotodocumentation.rest;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import javax.json.Json;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Executor;
import org.apache.http.client.fluent.Request;
import org.apache.http.impl.client.BasicCookieStore;

/**
 * 
 * <p>Copyright: Copyright (c) 2024</p>
 * <p>Company: heyday Marketing GmbH</p>
 * @author <a href="mailto:p.verboom@heyday.marketing">Patrick Verboom</a>
 * @version 1.0
 * 
 * created: 13 Nov 2024
 */
public abstract class AbstractRestTest extends AbstractTest {
	private static final Log LOG = LogFactory.getLog(AbstractRestTest.class);
	public static final String TEXT_PLAIN = "text/plain";

	private static Map<String, String> bearerToken = new HashMap<>();

	public HttpResponse executeRequest(Request request) throws IOException {
		var executor = Executor.newInstance();
		return executor.use(new BasicCookieStore()).execute(request).returnResponse();
	}

	protected String getAuthorization() {
		return getAuthorization(username, password);
	}

	protected String getAuthorization(String user, String pass) {

		if (!bearerToken.containsKey(user)) {
			String auth = user + ":" + pass;
			String encoded = Base64.getEncoder().encodeToString(auth.getBytes());
			String authorization = "Basic " + encoded;

			bearerToken.put(user, getBearerToken(authorization));
		}

		return "Bearer " + bearerToken.getOrDefault(user, "");
	}
	
	protected String getBasicHeader() {
		return getBasicHeader(username, password);
	}
	
	protected String getBasicHeader(String user, String pass) {
		String auth = user + ":" + pass;
		String encoded = Base64.getEncoder().encodeToString(auth.getBytes());
		return "Basic " + encoded;
	}

	protected String getBearerToken(String authorization) {
		try {
			String path = deploymentURL + "api/login";
			Request request = Request.Get(path).addHeader("Accept", "application/json; charset=utf-8")
					.addHeader("Authorization", authorization);

			HttpResponse httpResponse = executeRequest(request);
			int code = httpResponse.getStatusLine().getStatusCode();
			assertEquals(200, code);

			String bearerStr = getResponseText(httpResponse);

			try (var reader = Json.createReader(new StringReader(bearerStr));) {
				return reader.readObject().getString("accessToken");
			}
		} catch (IOException e) {
			LOG.error("Failed to get bearer token " + e.getMessage(), e);
			return "";
		}
	}

	protected byte[] getResponse(HttpResponse httpResponse) throws IOException {
		try (var output = new ByteArrayOutputStream(); var input = httpResponse.getEntity().getContent()) {
			input.transferTo(output);
			output.flush();
			return output.toByteArray();
		}
	}

	protected String getResponseText(HttpResponse httpResponse) throws IOException {
		String text;
		try (BufferedReader input = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()))) {
			text = input.lines().collect(Collectors.joining("\n"));
		}
		return text;
	}

	protected String getResponseText(HttpResponse httpResponse, Supplier<String> supplier) throws IOException {
		String text = getResponseText(httpResponse);
		writeJsonFile(text, supplier.get());
		return text;
	}

	protected String getResponseText(HttpResponse httpResponse, String name) throws IOException {
		String className = this.getClass().getName();
		return getResponseText(httpResponse, () -> className + "-" + name + ".json");
	}
	
	protected int customerCount() {
		return getCount("select count(*) from customer");
	}
	
	protected int pictureCount() {
		return getCount("select count(*) from picture");
	}
}
