#include <GL/glew.h>
#include "WindowManager.h"
#include "../Systems/Logger.h"
#include <GLFW/glfw3.h>

#include "Profiler.h"

namespace OX
{
    bool WindowManager::Init(const std::string &title, int width, int height)
    {
        m_width = width;
        m_height = height;

        if (!glfwInit()) {
            Logger::LogError("Failed to initialize GLFW");
            return false;
        }

        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
        glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

        //glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // REM title bar


        m_window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
        if (!m_window) {
            Logger::LogError("Failed to create GLFW window");
            glfwTerminate();
            return false;
        }

        glfwMakeContextCurrent(m_window);
        glfwSwapInterval(1); // Enable vsync

        glewExperimental = GL_TRUE;
        GLenum err = glewInit();
        if (err != GLEW_OK) {
            Logger::LogError("Failed to initialize GLEW: %s", reinterpret_cast<const char *>(glewGetErrorString(err)));
            return false;
        }

        glfwSetFramebufferSizeCallback(m_window, FramebufferSizeCallback);
        glfwSetWindowUserPointer(m_window, this);

        glEnable(GL_DEPTH_TEST);

        return true;
    }


    void WindowManager::SetWindowTitle(const std::string &title) const
    {
        if (m_window) {
            glfwSetWindowTitle(m_window, title.c_str());
        }
        else {
            Logger::LogWarning("Failed to set Window Title: 'Not Initialized'");
        }
    }

    void WindowManager::FramebufferSizeCallback(GLFWwindow *window, int width, int height)
    {
        OX_PROFILE_FUNCTION();

        auto *wm = static_cast<WindowManager *>(glfwGetWindowUserPointer(window));
        if (wm) {
            wm->SetSize(width, height);
        }
    }

    void WindowManager::SetSize(int width, int height)
    {
        OX_PROFILE_FUNCTION();

        m_width = width;
        m_height = height;
        glViewport(0, 0, width, height);
    }

    void WindowManager::PollEvents() const
    {
        OX_PROFILE_FUNCTION();

        glfwPollEvents();
    }

    bool WindowManager::ShouldClose() const
    {
        return glfwWindowShouldClose(m_window);
    }

    void WindowManager::BeginFrame() const
    {
        OX_PROFILE_FUNCTION();
        PollEvents();
        glViewport(0, 0, m_width, m_height);
        glClearColor(0.07f, 0.07f, 0.1f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }

    void WindowManager::EndFrame() const
    {
        OX_PROFILE_FUNCTION();

        glfwSwapBuffers(m_window);
    }

    void WindowManager::Shutdown()
    {
        if (m_window) {
            glfwDestroyWindow(m_window);
            m_window = nullptr;
        }
        glfwTerminate();
    }

    WindowManager::~WindowManager()
    {
        Shutdown();
    }
}
