package RestAPISchnittstelle;

import java.net.ConnectException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;

import Logik.ElternAccount;
import Logik.Kind;
import Logik.Mahlzeit;
import Logik.Tagesplan;
import com.google.gson.*;
import javafx.scene.control.Alert;

/**
 * @author Samuel Wolff
 */
public class RestApiClient implements IRestAPI{

	private final String urlBase = "https://pbg2h22awo.web.pb.bib.de/VPR_Schnittstelle/VPR_Schnittstelle/restAPI.php";

	private final int timeout = 10;

	private final HttpClient client;

	private final Gson gson;

	public RestApiClient(){
		client = HttpClient.newHttpClient();
		gson = new Gson();
	}

	public static void main(String[] args){

		RestApiClient client1 = new RestApiClient();

		client1.delete("Kind", 15);


		Tagesplan t = client1.getGerichteOnTag("2023-12-17");

		for(Mahlzeit m : t.getGerichte())
			System.out.println(m);
	}

	/**
	 * Methode für einen Get-Aufruf. Ruft alle Elemente einer Tabelle auf.
	 *
	 * @param controllerName Name des aufzurufenden Controllers
	 * @author Samuel Wolff
	 */
	@Override
	public String get(String controllerName) {
		URI apiUri = URI.create(String.format("%s/%s", urlBase, controllerName));

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());
			return httpResponse.body();
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return null;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Methode für einen Get-Aufruf. Ruft ein spezifisches Element auf.
	 *
	 * @param controllerName Name des aufzurufenden Controllers
	 * @param id Id der Aufzurufenden Zeile
	 * @author Samuel Wolff
	 */
	@Override
	public String get(String controllerName, int id) {
		URI apiUri = URI.create(String.format("%s/%s/%s", urlBase, controllerName, id));

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode() + httpResponse.body());

			return httpResponse.body();

			//System.out.println("Response Body: " + test);
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return null;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * --DEPRECATED--
	 * Methode für einen Get-Aufruf. Ruft ein spezielles Element auf.
	 *
	 * @param controllerName Name des aufzurufenden Controllers
	 * @param id Id der Aufzurufenden Zeile
	 * @param bezahlt TODO Warum ist das hier?
	 * @deprecated
	 * @author Samuel Wolff
	 */
	@Override
	public String get(String controllerName, int id, boolean bezahlt) {
		URI apiUri = URI.create(String.format("%s/%s?%s&%s", urlBase, controllerName, id, bezahlt));

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());
			return httpResponse.body();
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return null;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/***
	 * Ein gefilterter Get Aufruf
	 * @param controllerName
	 * @param params
	 * @return
	 * @author Sven Alteköster
	 */
	@Override
	public String get(String controllerName, String[] params) {
		String ende = "";
		for (String str : params) {
			ende += str + ",";
		}
		ende = ende.substring(0, ende.length() - 1);
		URI apiUri = URI.create(String.format("%s/%s?%s", urlBase, controllerName, ende));

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode() + httpResponse.body());

			return httpResponse.body();

			//System.out.println("Response Body: " + test);
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return null;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Methode für einen Put-Aufruf. Aktualisiert einen Eintrag.
	 *
	 * @param controllerName Name des aufzurufenden Controllers.
	 * @param id Id des zu änderenden Eintrags.
	 * @param jsonData JsonString mit den neuen Daten.
	 * @author Samuel Wolff
	 */
	@Override
	public void put(String controllerName, int id, String jsonData) {

		URI apiUri = URI.create(String.format("%s/%s/%s", urlBase,controllerName, id));

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .PUT(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Methode für einen Post-Aufruf. Fügt einen Eintrag in eine Datenbank hinzu.
	 *
	 * @param controllerName Name des aufzurufenden Controllers.
	 * @param jsonData JsonString mit den Daten des Eintrags.
	 * @author Samuel Wolff
	 */
	@Override
	public void post(String controllerName, String jsonData) {
		URI apiUri = URI.create(String.format("%s/%s", urlBase,controllerName));

		System.out.println(apiUri);

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .POST(HttpRequest.BodyPublishers.ofString(jsonData, StandardCharsets.UTF_8))
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Methode für einen Delete-Aufruf. Löscht einen Eintrag mit einer Id.
	 *
	 * @param controllerName Name des aufzurufenden Controllers
	 * @param id Id des zu löschenden Eintrags.
	 * @author Samuel Wolff
	 */
	@Override
	public void delete(String controllerName, int id) {
		URI apiUri = URI.create(String.format("%s/%s/%d", urlBase,controllerName, id));

		System.out.println(apiUri);

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .DELETE()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	/***
	 * Holt die nöchste Autoinkrement Id für den mitgegebenen Controller aus der Datenbank
	 * @param controllerName
	 * @return
	 * @author Samuel Wolff
	 */
	public int nextId(String controllerName){
		URI apiUri = URI.create(String.format("%s/%s/nextId", urlBase, controllerName));

		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());

			JsonElement jsonElement = JsonParser.parseString(httpResponse.body());
			JsonArray jsonArray = jsonElement.getAsJsonArray();

			JsonObject json = jsonArray.get(0).getAsJsonObject();

			return json.get("auto_increment").getAsInt();

		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return -1;
		}
		catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	/**
	 * Startet einen guckt ob die mitgegebenen Anmeldedaten in der Kombination existieren.
	 *
	 * @param credentials Die Anmeldedaten in Json-String form
	 * @return True oder false, je nach Erfolg des Anmeldeversuchs
	 * @author Samuel Wolff
	 */
	public boolean anmeldeVersuch(String credentials){

		JsonObject json = gson.fromJson(credentials, JsonObject.class);
		String benutzer = json.get("Benutzername").toString();
		benutzer = benutzer.substring(1, benutzer.length()-1);

		String passwort = json.get("passwort").toString();
		passwort = passwort.substring(1, passwort.length()-1);

		URI apiUri = URI.create(String.format("%s/Benutzer/anmeldeVersuch?Benutzername=%s&passwort=%s", urlBase, benutzer, passwort));
		System.out.println(apiUri);
		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());
			if(httpResponse.body().equals("true"))
				return true;
			else{
				Alert alert = new Alert(Alert.AlertType.INFORMATION);
				alert.setContentText("Falsche Anmeldedaten");
				alert.setHeaderText("Fehler!");
				alert.showAndWait();
				return false;
			}
		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return false;
		}
		catch (Exception e) {
			e.printStackTrace();
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Ein Uwuwarteter Fehler ist aufgetreten!");
			alert.showAndWait();
			return false;
		}
	}

	/**
	 * Holt alle Gerichte eines mitgegebenen Tages aus der Datenbank
	 *
	 * @param datum Das angeforderte Datum in String Form (YYYY-MM-DD)
	 * @return Ein Tagesplan Objekt mit allen Gerichten
	 * @author Samuel Wolff
	 */
	public Tagesplan getGerichteOnTag(String datum){

		URI apiUri = URI.create(String.format("%s/Tagesplan/getGerichteOnTag?datum=%s", urlBase, datum));
		System.out.println(apiUri);
		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .timeout(Duration.ofSeconds(timeout))
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());

			Tagesplan t = new Tagesplan(datum);

			JsonElement jsonElement = JsonParser.parseString(httpResponse.body());

			JsonArray json = jsonElement.getAsJsonArray();

			for(int i = 0; i< json.size(); i++){

				JsonObject o = json.get(i).getAsJsonObject();
				String name = o.get("name").getAsString();
				float preis = o.get("preis").getAsFloat();
				String beschreibung = o.get("beschreibung").getAsString();

				t.getGerichte().add(new Mahlzeit(name, preis, beschreibung));

			}

			return t;

		}
		catch(ConnectException conex){
			Alert alert = new Alert(Alert.AlertType.INFORMATION);
			alert.setContentText("Verbindung zum Server konnte nicht aufgebaut werden!");
			alert.showAndWait();
			return null;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Holt die Id des Gerichtes mit dem mitgegebenen Namen an einem mitgegebenen Tag und gibt sie zurück
	 * @param name
	 * @param datum
	 * @return
	 * @author Samuel Wolff
	 */
	public int getGerichtIdOnTag(String name, String datum){

		URI apiUri = URI.create(String.format("%s/Tagesplan/getGerichtIdOnTag?name=%s&datum=%s", urlBase, name, datum));
		System.out.println(apiUri);
		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .GET()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Response Body: " + httpResponse.body());

			JsonElement jsonElement = JsonParser.parseString(httpResponse.body());

			JsonArray json = jsonElement.getAsJsonArray();

			JsonObject o = json.get(0).getAsJsonObject();

			return o.get("id").getAsInt();

		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}

	/**
	 * Löscht ein Gericht mit der mitgebenen Id aus der Datenbank
	 * @param id
	 * @author Samuel Wolff
	 */
	public void deleteGericht(int id){
		URI apiUri = URI.create(String.format("%s/Tagesplan/%d", urlBase, id));
		System.out.println(apiUri);
		HttpRequest httpRequest = HttpRequest.newBuilder()
											 .uri(apiUri)
											 .header("Content-Type", "application/json")
											 .DELETE()
											 .build();

		try {
			// Send the request and get the response
			HttpResponse<String> httpResponse = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());

			// Print the response status code and body
			System.out.println("Status Code: " + httpResponse.statusCode());
			System.out.println("Delete Gericht: Response Body: " + httpResponse.body());


		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
