#pragma once

#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include "utils.h"

namespace kek {

typedef GenericCallable<GLFWwindow *> PeriodicCallback; // periodicCallback(GLFWwindow *window)
typedef GenericCallable<GLFWwindow *, int, int, int, int> KeyCallback; // keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
typedef GenericCallable<GLFWwindow *, unsigned int> KeyCharCallback; // keyCharCallback(GLFWwindow *window, unsigned int codepoint)
typedef GenericCallable<GLFWwindow *, double, double> MouseCallback; // mouseCallback(GLFWwindow *window, double x, double y)
typedef GenericCallable<GLFWwindow *, int, int, int> MouseButtonCallback; // void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods)

typedef unsigned int InputListener;
typedef int GLFWKey;
typedef int GLFWKeyState;
typedef unsigned int KeyBinding;
typedef unsigned int KeyboardCapture;

struct KeyBindingData {
	std::string name;
	GLFWKey key;
};

enum class GLFWCursorMode {
	CAPTURE = GLFW_CURSOR_DISABLED,
	FREE = GLFW_CURSOR_NORMAL,
	HIDDEN = GLFW_CURSOR_HIDDEN
};

enum class GLFWMouseButton {
	LEFT = GLFW_MOUSE_BUTTON_LEFT,
	RIGHT = GLFW_MOUSE_BUTTON_RIGHT,
	MIDDLE = GLFW_MOUSE_BUTTON_MIDDLE
};

}

namespace kek::Input {

void init();
void destroy();

InputListener addPeriodicCallback(PeriodicCallback callback);
void removePeriodicCallback(InputListener listener);

InputListener addKeyListener(KeyCallback callback);
void removeKeyListener(InputListener listener);

InputListener addKeyCharListener(KeyCharCallback callback);
void removeKeyCharListener(InputListener listener);

InputListener addMouseListener(MouseCallback callback);
void removeMouseListener(InputListener listener);

InputListener addMouseButtonListener(MouseButtonCallback callback);
void removeMouseButtonListener(InputListener listener);

KeyBinding createKeyBinding(std::string name, GLFWKey defaultKey);
void reassignKeyBinding(KeyBinding mapping, GLFWKey key);
KeyBindingData getKeyBinding(KeyBinding mapping);
GLFWKeyState getKeyState(KeyBinding mapping);

void setCursorMode(GLFWCursorMode mode);
GLFWCursorMode getCursorMode();

KeyboardCapture captureKeyboardInput(KeyCharCallback charCallback, KeyCallback keyCallback, Callable uncaptureCallback);
bool uncaptureKeyboardInput(KeyboardCapture capture);
bool isKeyboardCaptured();

}
