#pragma once

#include "../shader_backend.hpp"

#ifdef __APPLE__
#include <OpenGL/gl3.h>
#else
#include <SDL3/SDL_opengl.h>
#endif

namespace Rendering {

/**
 * @brief Backend de shaders usando OpenGL 3.3 Core Profile
 *
 * Implementa el renderizado de shaders usando APIs modernas de OpenGL:
 * - VAO (Vertex Array Objects)
 * - VBO (Vertex Buffer Objects)
 * - Shaders GLSL #version 330 core
 */
class OpenGLShader : public ShaderBackend {
    public:
        OpenGLShader() = default;
        ~OpenGLShader() override;

        bool init(SDL_Window* window,
            SDL_Texture* texture,
            const std::string& vertex_source,
            const std::string& fragment_source) override;

        void render() override;
        void setTextureSize(float width, float height) override;
        void cleanup() override;
        bool isHardwareAccelerated() const override { return is_initialized_; }

    private:
        // Funciones auxiliares
        bool initGLExtensions();
        GLuint compileShader(const std::string& source, GLenum shader_type);
        GLuint linkProgram(GLuint vertex_shader, GLuint fragment_shader);
        void createQuadGeometry();
        GLuint getTextureID(SDL_Texture* texture);
        void checkGLError(const char* operation);

        // Estado SDL
        SDL_Window* window_ = nullptr;
        SDL_Renderer* renderer_ = nullptr;
        SDL_Texture* back_buffer_ = nullptr;

        // Estado OpenGL
        GLuint program_id_ = 0;
        GLuint vao_ = 0;  // Vertex Array Object
        GLuint vbo_ = 0;  // Vertex Buffer Object
        GLuint ebo_ = 0;  // Element Buffer Object

        // Ubicaciones de uniforms
        GLint texture_size_location_ = -1;

        // Tamaños
        int window_width_ = 0;
        int window_height_ = 0;
        float texture_width_ = 0.0f;
        float texture_height_ = 0.0f;

        // Estado
        bool is_initialized_ = false;

#ifndef __APPLE__
        // Punteros a funciones OpenGL en Windows/Linux
        PFNGLCREATESHADERPROC glCreateShader = nullptr;
        PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
        PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
        PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
        PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
        PFNGLDELETESHADERPROC glDeleteShader = nullptr;
        PFNGLATTACHSHADERPROC glAttachShader = nullptr;
        PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
        PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
        PFNGLVALIDATEPROGRAMPROC glValidateProgram = nullptr;
        PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
        PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
        PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
        PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr;
        PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
        PFNGLUNIFORM2FPROC glUniform2f = nullptr;
        PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
        PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
        PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;
        PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
        PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
        PFNGLBUFFERDATAPROC glBufferData = nullptr;
        PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;
        PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
        PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
#endif
};

}  // namespace Rendering
