#include <pch.hpp>

#include "application.hpp"
#include "logging.hpp"
#include <input/linux_input.hpp>

#include <GLFW/glfw3.h>

namespace OpenEngine {
    
    Input* Input::instance = new LinuxInput();

    bool LinuxInput::IsKeyPressedImpl(int keycode)
    {
        auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
        auto state = glfwGetKey(window, keycode);

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

    bool LinuxInput::IsMouseButtonPressedImpl(int keycode)
    {
        auto window = static_cast<GLFWwindow*>(Application::Get().GetWindow().GetNativeWindow());
        auto state = glfwGetMouseButton(window, keycode);

        return state == GLFW_PRESS;
    }

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

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

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

    float LinuxInput::GetMouseXImpl()
    {
        auto [x, y] = GetMousePositionImpl();

        return (float)x;
    }

    float LinuxInput::GetMouseYImpl()
    {
        auto [x, y] = GetMousePositionImpl();

        return (float)y;

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

    bool LinuxInput::JoystickExistsImpl(unsigned int joystick)
    {
        bool status = glfwJoystickPresent(joystick);

        return status;
    }

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

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

        return axes;
    }

    float LinuxInput::GetJoystickAxisImpl(unsigned int joystick, unsigned int axis)
    {
        if (!JoystickExistsImpl(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 LinuxInput::GetJoystickNameImpl(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> LinuxInput::GetJoystickListImpl()
    {
        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 LinuxInput::GetJoystickAxesCountImpl(unsigned int joystick)
    {
        if (!JoystickExistsImpl(joystick)) {
            OE_CORE_WARN("Joystick number {} is not present.", joystick);
            return 0;
        }

        int count;
        glfwGetJoystickAxes(joystick, &count);

        return count;
    }

    bool LinuxInput::IsJoystickButtonPressedImpl(unsigned int joystick, unsigned int button)
    {
        if (!JoystickExistsImpl(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];
    }
}
