#pragma once

#ifdef _WIN32
    #ifndef WIN32_LEAN_AND_MEAN
        #define WIN32_LEAN_AND_MEAN
    #endif
    #include <windows.h>
    #include <GL/gl.h>
    #include <GL/glext.h>

    extern PFNGLATTACHSHADERPROC        fn_glAttachShader;
    extern PFNGLBINDBUFFERPROC          fn_glBindBuffer;
    extern PFNGLBINDFRAMEBUFFERPROC     fn_glBindFramebuffer;
    extern PFNGLBINDVERTEXARRAYPROC     fn_glBindVertexArray;
    extern PFNGLCOMPILESHADERPROC       fn_glCompileShader;
    extern PFNGLCREATEPROGRAMPROC       fn_glCreateProgram;
    extern PFNGLCREATESHADERPROC        fn_glCreateShader;
    extern PFNGLDELETEBUFFERSPROC       fn_glDeleteBuffers;
    extern PFNGLDELETEFRAMEBUFFERSPROC  fn_glDeleteFramebuffers;
    extern PFNGLDELETEPROGRAMPROC       fn_glDeleteProgram;
    extern PFNGLDELETESHADERPROC        fn_glDeleteShader;
    extern PFNGLDELETEVERTEXARRAYSPROC  fn_glDeleteVertexArrays;
    extern PFNGLFRAMEBUFFERTEXTURE2DPROC fn_glFramebufferTexture2D;
    extern PFNGLGENBUFFERSPROC          fn_glGenBuffers;
    extern PFNGLGENFRAMEBUFFERSPROC     fn_glGenFramebuffers;
    extern PFNGLGENVERTEXARRAYSPROC     fn_glGenVertexArrays;
    extern PFNGLGETPROGRAMINFOLOGPROC   fn_glGetProgramInfoLog;
    extern PFNGLGETPROGRAMIVPROC        fn_glGetProgramiv;
    extern PFNGLGETSHADERINFOLOGPROC    fn_glGetShaderInfoLog;
    extern PFNGLGETSHADERIVPROC         fn_glGetShaderiv;
    extern PFNGLGETUNIFORMLOCATIONPROC  fn_glGetUniformLocation;
    extern PFNGLLINKPROGRAMPROC         fn_glLinkProgram;
    extern PFNGLSHADERSOURCEPROC        fn_glShaderSource;
    extern PFNGLUNIFORM1FPROC           fn_glUniform1f;
    extern PFNGLUNIFORM1IPROC           fn_glUniform1i;
    extern PFNGLUNIFORM1UIPROC          fn_glUniform1ui;
    extern PFNGLUNIFORM2FPROC           fn_glUniform2f;
    extern PFNGLUNIFORM3FPROC           fn_glUniform3f;
    extern PFNGLUNIFORM4FPROC           fn_glUniform4f;
    extern PFNGLUNIFORM4FVPROC          fn_glUniform4fv;
    extern PFNGLUNIFORMMATRIX4FVPROC    fn_glUniformMatrix4fv;
    extern PFNGLUSEPROGRAMPROC          fn_glUseProgram;
    // Texture (gl_texture_load — issue 0026)
    extern PFNGLACTIVETEXTUREPROC       fn_glActiveTexture;
    extern PFNGLGENERATEMIPMAPPROC      fn_glGenerateMipmap;
    // Buffers / VAO data + draw + vertex attributes (graph_renderer)
    extern PFNGLBUFFERDATAPROC          fn_glBufferData;
    extern PFNGLDRAWARRAYSINSTANCEDPROC fn_glDrawArraysInstanced;
    extern PFNGLENABLEVERTEXATTRIBARRAYPROC fn_glEnableVertexAttribArray;
    extern PFNGLVERTEXATTRIBDIVISORPROC fn_glVertexAttribDivisor;
    extern PFNGLVERTEXATTRIBPOINTERPROC fn_glVertexAttribPointer;
    // Renderbuffer / framebuffer texture
    extern PFNGLBINDRENDERBUFFERPROC    fn_glBindRenderbuffer;
    extern PFNGLDELETERENDERBUFFERSPROC fn_glDeleteRenderbuffers;
    extern PFNGLFRAMEBUFFERRENDERBUFFERPROC fn_glFramebufferRenderbuffer;
    extern PFNGLGENRENDERBUFFERSPROC    fn_glGenRenderbuffers;
    extern PFNGLRENDERBUFFERSTORAGEPROC fn_glRenderbufferStorage;
    extern PFNGLFRAMEBUFFERTEXTUREPROC  fn_glFramebufferTexture; // sin "2D"
    // Vertex pulling — issue 0049d (TBO de posiciones + sub-data streaming)
    extern PFNGLBUFFERSUBDATAPROC       fn_glBufferSubData;
    extern PFNGLVERTEXATTRIBIPOINTERPROC fn_glVertexAttribIPointer;
    extern PFNGLTEXBUFFERPROC           fn_glTexBuffer;
    // Compute shaders + SSBOs — issue 0049h (graph_force_layout_gpu)
    extern PFNGLDISPATCHCOMPUTEPROC     fn_glDispatchCompute;
    extern PFNGLMEMORYBARRIERPROC       fn_glMemoryBarrier;
    extern PFNGLBINDBUFFERBASEPROC      fn_glBindBufferBase;
    extern PFNGLGETBUFFERSUBDATAPROC    fn_glGetBufferSubData;

    #define glAttachShader          fn_glAttachShader
    #define glBindBuffer            fn_glBindBuffer
    #define glBindFramebuffer       fn_glBindFramebuffer
    #define glBindVertexArray       fn_glBindVertexArray
    #define glCompileShader         fn_glCompileShader
    #define glCreateProgram         fn_glCreateProgram
    #define glCreateShader          fn_glCreateShader
    #define glDeleteBuffers         fn_glDeleteBuffers
    #define glDeleteFramebuffers    fn_glDeleteFramebuffers
    #define glDeleteProgram         fn_glDeleteProgram
    #define glDeleteShader          fn_glDeleteShader
    #define glDeleteVertexArrays    fn_glDeleteVertexArrays
    #define glFramebufferTexture2D  fn_glFramebufferTexture2D
    #define glGenBuffers            fn_glGenBuffers
    #define glGenFramebuffers       fn_glGenFramebuffers
    #define glGenVertexArrays       fn_glGenVertexArrays
    #define glGetProgramInfoLog     fn_glGetProgramInfoLog
    #define glGetProgramiv          fn_glGetProgramiv
    #define glGetShaderInfoLog      fn_glGetShaderInfoLog
    #define glGetShaderiv           fn_glGetShaderiv
    #define glGetUniformLocation    fn_glGetUniformLocation
    #define glLinkProgram           fn_glLinkProgram
    #define glShaderSource          fn_glShaderSource
    #define glUniform1f             fn_glUniform1f
    #define glUniform1i             fn_glUniform1i
    #define glUniform1ui            fn_glUniform1ui
    #define glUniform2f             fn_glUniform2f
    #define glUniform3f             fn_glUniform3f
    #define glUniform4f             fn_glUniform4f
    #define glUniform4fv            fn_glUniform4fv
    #define glUniformMatrix4fv      fn_glUniformMatrix4fv
    #define glUseProgram            fn_glUseProgram
    #define glActiveTexture         fn_glActiveTexture
    #define glGenerateMipmap        fn_glGenerateMipmap
    #define glBufferData            fn_glBufferData
    #define glDrawArraysInstanced   fn_glDrawArraysInstanced
    #define glEnableVertexAttribArray fn_glEnableVertexAttribArray
    #define glVertexAttribDivisor   fn_glVertexAttribDivisor
    #define glVertexAttribPointer   fn_glVertexAttribPointer
    #define glBindRenderbuffer      fn_glBindRenderbuffer
    #define glDeleteRenderbuffers   fn_glDeleteRenderbuffers
    #define glFramebufferRenderbuffer fn_glFramebufferRenderbuffer
    #define glGenRenderbuffers      fn_glGenRenderbuffers
    #define glRenderbufferStorage   fn_glRenderbufferStorage
    #define glFramebufferTexture    fn_glFramebufferTexture
    #define glBufferSubData         fn_glBufferSubData
    #define glVertexAttribIPointer  fn_glVertexAttribIPointer
    #define glTexBuffer             fn_glTexBuffer
    #define glDispatchCompute       fn_glDispatchCompute
    #define glMemoryBarrier         fn_glMemoryBarrier
    #define glBindBufferBase        fn_glBindBufferBase
    #define glGetBufferSubData      fn_glGetBufferSubData
#else
    #define GL_GLEXT_PROTOTYPES
    #include <GL/gl.h>
    #include <GL/glext.h>
#endif

namespace fn::gfx {

// Load OpenGL 2.0+ function pointers. On Linux it's a no-op (symbols resolved
// statically via GL_GLEXT_PROTOTYPES). On Windows it uses wglGetProcAddress;
// the GL context must be current before calling.
bool gl_loader_init();

} // namespace fn::gfx
