#include <pch.hpp>

#include <core.hpp>
#include <input/input_system.hpp>
#include <input/mouse_codes.hpp>
#include <input/keycodes.hpp>
#include <application.hpp>
#include <logging.hpp>

#include <GLFW/glfw3.h>

namespace OpenEngine {

    bool Input::IsKeyPressed(KeyCode keycode)
    {
        auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
        auto state = glfwGetKey(window, static_cast<int32_t>(keycode));

        return state == GLFW_PRESS || state == GLFW_REPEAT;
    }

    bool Input::IsMouseButtonPressed(MouseCode keycode)
    {
        auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
        auto state = glfwGetMouseButton(window, static_cast<int32_t>(keycode));

        return state == GLFW_PRESS;
    }

    std::pair<float, float> Input::GetMousePosition()
    {
        auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());

        double x, y;
        glfwGetCursorPos(window, &x, &y);

        return {(float)x, (float)y};
    }

    float Input::GetMouseX()
    {
        auto [x, y] = GetMousePosition();

        return (float)x;
    }

    float Input::GetMouseY()
    {
        auto [x, y] = GetMousePosition();

        return (float)y;

        int count;
        auto axes = glfwGetJoystickAxes(0, &count);
    }

    bool Input::JoystickExists(unsigned int joystick)
    {
        bool status = glfwJoystickPresent(joystick);

        return status;
    }

    const float* Input::GetJoystickAxes(unsigned int joystick)
    {
        if (!JoystickExists(joystick)) {
            OE_CORE_WARN("Joystick number {} is not present.", joystick);
            return nullptr;
        }

        int count;
        auto axes = glfwGetJoystickAxes(joystick, &count);

        return axes;
    }

    float Input::GetJoystickAxis(unsigned int joystick, unsigned int axis)
    {
        if (!JoystickExists(joystick)) {
            OE_CORE_WARN("Joystick number {} is not present.", joystick);
            return 0.0f;
        }

        int count;
        auto axes = glfwGetJoystickAxes(joystick, &count);

        if (axis >= count) {
            OE_CORE_WARN("Axis number {} is greate than axis count ({})", axis, count);
            return 0.0f;
        }

        return axes[axis];
    }

    const std::string Input::GetJoystickName(unsigned int joystick)
    {
        auto name = glfwGetJoystickName(joystick);

        if (!name) {
            OE_CORE_WARN("Joystick number {} is not present.", joystick);
            return "N/A";
        }

        return name;
    }

    std::map<unsigned int, std::string> Input::GetJoystickList()
    {
        std::map<unsigned int, std::string> joysticks;

        for (size_t i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
            auto name = glfwGetJoystickName(i);

            if (name)
                joysticks[i] = name;
        }

        return joysticks;
    }

    unsigned int Input::GetJoystickAxesCount(unsigned int joystick)
    {
        if (!JoystickExists(joystick)) {
            OE_CORE_WARN("Joystick number {} is not present.", joystick);
            return 0;
        }

        int count;
        glfwGetJoystickAxes(joystick, &count);

        return count;
    }

    bool Input::IsJoystickButtonPressed(unsigned int joystick, unsigned int button)
    {
        if (!JoystickExists(joystick))
            OE_CORE_WARN("Joystick number {} is not present.", joystick);

        int count;
        const unsigned char* buttons = glfwGetJoystickButtons(joystick, &count);

        if (button >= count)
            OE_CORE_WARN("Button number {} is greater than button count ({}).", button, count);

        return buttons[button];
    }
}
