package de.fe1k.game9.commands;

import de.fe1k.game9.events.Event;
import de.fe1k.game9.events.EventListener;
import de.fe1k.game9.events.EventUpdate;
import de.nerogar.noise.input.KeyboardKeyEvent;
import de.nerogar.noise.render.GLWindow;
import de.nerogar.noise.render.fontRenderer.Font;
import de.nerogar.noise.render.fontRenderer.FontRenderableString;
import de.nerogar.noise.util.Color;
import de.nerogar.noise.util.Logger;
import de.nerogar.noise.util.Matrix4f;
import de.nerogar.noise.util.Matrix4fUtils;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque;
import java.util.Queue;

import static org.lwjgl.glfw.GLFW.*;

public class Console {
	private GLWindow window;
	private String   input;
	private Matrix4f projectionMatrix;
	private Color    inputColor;
	private Color    linesColor;
	private Font     font;

	private boolean                     enabled;
	private Queue<FontRenderableString> lines;
	private EventListener<EventUpdate> eventUpdate = this::update;

	private String loggerText;
	private ByteArrayOutputStream loggerStream;

	private static final int numLines = 10;
	private static final int fontSize = 15;

	public Console(GLWindow window) {
		this.window = window;
		input = "";
		loggerText = "";
		projectionMatrix = new Matrix4f();
		inputColor = new Color(0.0f, 1.0f, 0.0f, 1.0f);
		linesColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
		font = new Font("consolas", fontSize);
		enabled = false;
		lines = new ArrayDeque<>();

		updateProjectionMatrix(window.getWidth(), window.getHeight());
		Event.register(EventUpdate.class, eventUpdate);

		loggerStream = new ByteArrayOutputStream();
		Logger.addStream(Logger.WARNING, new PrintStream(loggerStream));
	}

	private void addLine(String text) {
		FontRenderableString string = new FontRenderableString(font, text, linesColor, projectionMatrix, 1f, 1f);
		lines.add(string);
	}

	private void update(EventUpdate updateEvent) {
		loggerText += new String(loggerStream.toByteArray(), StandardCharsets.UTF_8);
		loggerStream.reset();
		while (loggerText.contains("\n")) {
			String[] parts = loggerText.split("\n", 2);
			loggerText = parts[1];
			addLine(parts[0]);
		}

		String newText = window.getInputHandler().getInputText();
		for (KeyboardKeyEvent keyEvent : window.getInputHandler().getKeyboardKeyEvents()) {
			boolean isTriggered = keyEvent.action == GLFW_PRESS || keyEvent.action == GLFW_REPEAT;
			if (!isTriggered) continue;
			if (keyEvent.key == GLFW_KEY_TAB) {
				enabled = !enabled;
			}
			if (!enabled) return;
			if (input.isEmpty()) continue;
			if (keyEvent.key == GLFW_KEY_BACKSPACE) {
				input = input.substring(0, input.length() - 1);
			} else if (keyEvent.key == GLFW_KEY_ENTER || keyEvent.key == GLFW_KEY_KP_ENTER) {
				addLine("> " + input);
				parse(input.toLowerCase());
				input = "";
			}
		}
		if (!enabled) return;
		if (newText.matches("\\A\\p{ASCII}*\\z")) {
			// only ASCII support
			input += newText;
		}
	}

	private void parse(String text) {
		String[] args = text.split(" ", 2);
		ConsoleCommands command = ConsoleCommands.getByName(args[0]);
		if (command == null) {
			Logger.getErrorStream().printf("Unknown command: %s\n", args[0]);
		} else {
			command.getCommandConsumer().accept(args);
		}
	}

	public void render() {
		while (lines.size() > numLines) lines.poll().cleanup();
		if (!enabled) return;
		int margin = 8;
		int spacer = fontSize + 3;
		int i = 1;
		for (FontRenderableString line : lines) {
			line.render(margin, window.getHeight() - i*spacer - margin);
			i++;
		}
		FontRenderableString string = new FontRenderableString(font, "> " + input, inputColor, projectionMatrix, 1f, 1f);
		string.render(margin, window.getHeight() - i*spacer - margin);
		string.cleanup();
	}

	public void updateProjectionMatrix(int width, int height) {
		Matrix4fUtils.setOrthographicProjection(projectionMatrix, 0f, width, height, 0, 1, -1);
	}
}

@@ -511,116 +511,8 @@
 s;%0A%0A
-import java.io.ByteArrayOutputStream;%0Aimport java.io.PrintStream;%0Aimport java.nio.charset.StandardCharsets;%0A
 impo
@@ -536,16 +536,16 @@
 yDeque;%0A
+
 import j
@@ -919,16 +919,17 @@
 tUpdate%3E
+ 
  eventUp
@@ -954,82 +954,8 @@
 e;%0A%0A
-%09private String loggerText;%0A%09private ByteArrayOutputStream loggerStream;%0A%0A
 %09pri
@@ -1110,27 +1110,8 @@
 %22%22;%0A
-%09%09loggerText = %22%22;%0A
 %09%09pr
@@ -1454,54 +1454,8 @@
 );%0A%0A
-%09%09loggerStream = new ByteArrayOutputStream();%0A
 %09%09Lo
@@ -1462,22 +1462,24 @@
 gger.add
-Stream
+Listener
 (Logger.
@@ -1491,37 +1491,21 @@
 NG, 
-new PrintStream(loggerStream)
+this::addLine
 );%0A%09
@@ -1729,310 +1729,8 @@
 ) %7B%0A
-%09%09loggerText += new String(loggerStream.toByteArray(), StandardCharsets.UTF_8);%0A%09%09loggerStream.reset();%0A%09%09while (loggerText.contains(%22%5Cn%22)) %7B%0A%09%09%09String%5B%5D parts = loggerText.split(%22%5Cn%22, 2);%0A%09%09%09loggerText = parts%5B1%5D;%0A%09%09%09addLine(parts%5B0%5D);%0A%09%09%7D%0A%0A%09%09String newText = window.getInputHandler().getInputText();%0A
 %09%09fo
@@ -2321,20 +2321,80 @@
 %22;%0A%09%09%09%7D%0A
-
 %09%09%7D%0A
+%09%09String newText = window.getInputHandler().getInputText();%0A
 %09%09if (!e

update Console to use new Logger.addListener method