
#ifndef MAIN_LINUX_H
#define MAIN_LINUX_H

// Headers pour X11
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/extensions/xf86vmode.h>  // Pour le mode plein écran

// Headers pour OpenGL
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glx.h>

// Pour la gestion des erreurs
#include <fstream>
#include <cstdlib>
#include <iostream>

static std::ofstream err_main("err_main.txt");

/*
note : je ne suis pas familier de linux.
> il faut, je crois, ajouter les flags de compilations suivants : -lX11 -lGL -lGLEW -lXxf86vm
*/
// Structure pour stocker le contexte OpenGL et la fenêtre X11
typedef struct {
    Display* display;
    Window window;
    GLXContext glContext;
    int screen;
    XVisualInfo* visual;
    XF86VidModeModeInfo originalMode;  // Pour restaurer le mode d'affichage en plein écran
    bool fullscreen;
} OpenGLContext;

// Variables globales
static OpenGLContext m_context;
static const char* m_title = "scene de base";
static int m_window_w = 800;
static int m_window_h = 480;

// Déclarations des fonctions
bool createOpenGLContext();
bool createWindow(const char* title, bool fullscreen, int width, int height);
void close(const char* title);
void toggleFullscreen();

// Gestion des événements X11
void handleEvents() {
    XEvent event;
    while (XPending(m_context.display)) {
        XNextEvent(m_context.display, &event);
        switch (event.type) {
            case KeyPress: {
                KeySym key = XLookupKeysym(&event.xkey, 0);
                if (key == XK_Escape) {
                    close(m_title);
                } else if (key == XK_F1) {
                    toggleFullscreen();
                }
                break;
            }
            case DestroyNotify:
                close(m_title);
                break;
        }
    }
}

// Fonction pour basculer en mode plein écran
void toggleFullscreen() {
    if (m_context.fullscreen) {
        // Retour au mode fenêtré
        XF86VidModeSwitchToMode(m_context.display, m_context.screen, &m_context.originalMode);
        XMoveResizeWindow(
            m_context.display,
            m_context.window,
            0, 0,
            m_window_w, m_window_h
        );
    } else {
        // Passage en mode plein écran
        XF86VidModeModeInfo** modes;
        int modeNum;
        XF86VidModeGetAllModeLines(m_context.display, m_context.screen, &modeNum, &modes);
        m_context.originalMode = *modes[0];  // Sauvegarde du mode original
        XF86VidModeSwitchToMode(m_context.display, m_context.screen, modes[0]);
        XMoveResizeWindow(
            m_context.display,
            m_context.window,
            0, 0,
            modes[0]->hdisplay, modes[0]->vdisplay
        );
        XFree(modes);
    }
    m_context.fullscreen = !m_context.fullscreen;
}

// Fonction pour initialiser le contexte OpenGL
bool createOpenGLContext() {
    // Liste des attributs pour le contexte OpenGL 3.2
    int attribList[] = {
        GLX_RGBA,
        GLX_DOUBLEBUFFER,
        GLX_DEPTH_SIZE, 24,
        GLX_RED_SIZE, 8,
        GLX_GREEN_SIZE, 8,
        GLX_BLUE_SIZE, 8,
        GLX_ALPHA_SIZE, 8,
        None
    };

    // Récupérer un visual compatible
    m_context.visual = glXChooseVisual(m_context.display, m_context.screen, attribList);
    if (!m_context.visual) {
        err_main << "Erreur : Aucun visual OpenGL compatible trouvé." << std::endl;
        return false;
    }

    // Créer le contexte OpenGL
    m_context.glContext = glXCreateContext(m_context.display, m_context.visual, NULL, GL_TRUE);
    if (!m_context.glContext) {
        err_main << "Erreur : Impossible de créer le contexte OpenGL." << std::endl;
        return false;
    }

    // Activer le contexte
    if (!glXMakeCurrent(m_context.display, m_context.window, m_context.glContext)) {
        err_main << "Erreur : Impossible d'activer le contexte OpenGL." << std::endl;
        return false;
    }

    // Initialiser GLEW
    glewExperimental = GL_TRUE;
    if (glewInit() != GLEW_OK) {
        err_main << "Erreur : Impossible d'initialiser GLEW." << std::endl;
        return false;
    }

    // Vérifier la version d'OpenGL
    int glVersion[2] = { -1, -1 };
    glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]);
    glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]);
    err_main << "Using OpenGL: " << glVersion[0] << "." << glVersion[1] << std::endl;

    return true;
}

// Fonction pour créer une fenêtre
bool createWindow(const char* title, bool fullscreen, int width, int height) {
    m_context.display = XOpenDisplay(NULL);
    if (!m_context.display) {
        err_main << "Erreur : Impossible d'ouvrir le display X11." << std::endl;
        return false;
    }

    m_context.screen = DefaultScreen(m_context.display);

    // Créer une fenêtre X11
    XSetWindowAttributes windowAttr;
    windowAttr.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask;
    windowAttr.background_pixmap = None;
    windowAttr.background_pixel = BlackPixel(m_context.display, m_context.screen);

    m_context.window = XCreateWindow(
        m_context.display,
        RootWindow(m_context.display, m_context.screen),
        0, 0, width, height,
        0,
        CopyFromParent,
        InputOutput,
        CopyFromParent,
        CWEventMask | CWBackPixmap | CWBackPixel,
        &windowAttr
    );

    // Définir le titre de la fenêtre
    XStoreName(m_context.display, m_context.window, title);

    // Basculer en mode plein écran si demandé
    if (fullscreen) {
        toggleFullscreen();
    }

    // Afficher la fenêtre
    XMapWindow(m_context.display, m_context.window);

    // Initialiser le contexte OpenGL
    if (!createOpenGLContext()) {
        return false;
    }

    return true;
}

// Fonction pour fermer la fenêtre et libérer les ressources
void close(const char* title) {
    glXMakeCurrent(m_context.display, None, NULL);
    glXDestroyContext(m_context.display, m_context.glContext);
    XDestroyWindow(m_context.display, m_context.window);
    XCloseDisplay(m_context.display);
    exit(0);
}

// Boucle principale
int main() {
    // Créer une fenêtre (fenêtrée par défaut)
    if (!createWindow(m_title, false, m_window_w, m_window_h)) {
        return 1;
    }

    // Boucle principale
    while (true) {
        // Gérer les événements
        handleEvents();

        // Dessiner
        glClearColor(0.5f, 0.7f, 0.9f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        glXSwapBuffers(m_context.display, m_context.window);
    }

    return 0;
}

#endif  // MAIN_LINUX_H
