/*
 * Created by Brett on 28/11/23.
 * Licensed under GNU General Public License V3.0
 * See LICENSE file for license detail
 */
#include <blt/gfx/window.h>
#include <blt/std/assert.h>
#include <blt/std/logging.h>

void error_callback(int error, const char* description)
{
    BLT_ERROR("GLFW Error (%d): %s", error, description);
    std::abort();
}

namespace blt::gfx
{
    // because we aren't meant to have multiple GLFW windows (especially with GLAD) we will keep the window as global state.1
    struct
    {
        GLFWwindow* window;
        std::int32_t width;
        std::int32_t height;
    } window_state;
    
    void create_callbacks()
    {
    
    }
    
    void init(const window_data& data)
    {
        /* -- Setup Error Callback -- */
        glfwSetErrorCallback(error_callback);
        BLT_ASSERT(glfwInit() && "Unable to init GLFW. Aborting.");
        
        /* -- Setup Window Context -- */
        glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, data.context.GL_MAJOR);
        glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, data.context.GL_MINOR);
        glfwWindowHint(GLFW_DOUBLEBUFFER, data.context.DOUBLE_BUFFER);
        glfwWindowHint(GLFW_OPENGL_PROFILE, data.context.GL_PROFILE);
        
        /* -- Create the Window -- */
        window_state.window = glfwCreateWindow(data.width, data.height, data.title.c_str(), nullptr, nullptr);
        BLT_ASSERT(window_state.window && "Unable to create GLFW window.");
        
        /* -- Set Window Specifics + OpenGL -- */
        glfwMakeContextCurrent(window_state.window);
        glfwSwapInterval(data.sync_interval);
        gladLoadGL(glfwGetProcAddress);
        
        create_callbacks();
        
        /* -- Call User Provided post-window-init function  -- */
        data.init();
        
        /* -- General Loop -- */
        while (!glfwWindowShouldClose(window_state.window))
        {
            /* -- Get the current framebuffer size, update the global width/height state, along with OpenGL viewport -- */
            glfwGetFramebufferSize(window_state.window, &window_state.width, &window_state.height);
            glViewport(0, 0, window_state.width, window_state.height);
            
            /* -- Call user update function -- */
            data.update(window_state.width, window_state.height);
            
            /* -- Update GLFW state -- */
            glfwSwapBuffers(window_state.window);
            glfwPollEvents();
        }
    }
    
    void cleanup()
    {
        glfwDestroyWindow(window_state.window);
        glfwTerminate();
    }
}
