//
// Created by sebastian on 02.08.26.
//

#include "Keyboard.h"

#include "imgui_impl_glfw.h"
#include "core/Window.h"
#include "GLFW/glfw3.h"

engine::Keyboard::Keyboard(engine::Window &window) {
    window.setKeyboard(this);
    addKeyListener(window);
    addTextListener(window);
}

void engine::Keyboard::update() {
    keysPressedThisFrame.clear();
    keysRepeatedThisFrame.clear();
    charsThisFrame.clear();
    keysReleasedThisFrame.clear();
}

bool engine::Keyboard::isKeyDown(const int key) const {
    return keysDown.contains(key);
}

const std::vector<int> & engine::Keyboard::getCharsThisFrame() {
    return charsThisFrame;
}

auto engine::Keyboard::keyPressEvent(const int key) const -> bool {
    return keysPressedThisFrame.contains(key);
}

auto engine::Keyboard::keyPressEvent(const int key, bool checkRepeats) const -> bool {
    return keysPressedThisFrame.contains(key) || (checkRepeats && keysRepeatedThisFrame.contains(key));
}

bool engine::Keyboard::keyReleaseEvent(const int key) const {
    return keysReleasedThisFrame.contains(key);
}

void engine::Keyboard::addTextListener(Window &window) {
    glfwSetCharCallback(window.getHandle(), [](GLFWwindow* handle, unsigned int key) {
        ImGui_ImplGlfw_CharCallback(handle, key);
        auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
        if (!target || !target->keyboard) return;

        target->keyboard->reportChar(key);
    });
}

void engine::Keyboard::addKeyListener(Window &window) {
    glfwSetKeyCallback(window.getHandle(), [](GLFWwindow* handle, int key, int scancode, int action, int mods) {
        ImGui_ImplGlfw_KeyCallback(handle, key, scancode, action, mods);
        auto* target = static_cast<Window::CallbackTarget*>(glfwGetWindowUserPointer(handle));
        if (!target || !target->keyboard) return;

        if (action == GLFW_PRESS) target->keyboard->reportKeyPress(key);
        else if (action == GLFW_RELEASE) target->keyboard->reportKeyRelease(key);
        else if (action == GLFW_REPEAT) target->keyboard->reportKeyRepeat(key);
    });
}

void engine::Keyboard::reportKeyPress(int key) {
    keysDown.insert(key);
    keysPressedThisFrame.insert(key);
}

void engine::Keyboard::reportKeyRelease(int key) {
    keysDown.erase(key);
    keysReleasedThisFrame.insert(key);
}

void engine::Keyboard::reportKeyRepeat(int key) {
    keysRepeatedThisFrame.insert(key);
}

void engine::Keyboard::reportChar(int key) {
    charsThisFrame.push_back(key);
}
