#include <GL/gl.h>
#include <GL/glu.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <vector>
#include <iostream>

const int WIDTH = 800;
const int HEIGHT = 600;

void readPixelsToMatrix(std::vector<unsigned char> &pixelData, int width, int height) {
    glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixelData.data());
}

int main() {
    // Open a connection to the X server
    Display *display = XOpenDisplay(nullptr);
    if (display == nullptr) {
        std::cerr << "Failed to open X display" << std::endl;
        return -1;
    }

    // Get the root window
    Window root = DefaultRootWindow(display);

    // Set visual attributes
    GLint attributes[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
    XVisualInfo *visual = glXChooseVisual(display, 0, attributes);
    if (visual == nullptr) {
        std::cerr << "No appropriate visual found" << std::endl;
        return -1;
    }

    // Create a colormap
    Colormap colormap = XCreateColormap(display, root, visual->visual, AllocNone);

    // Set window attributes
    XSetWindowAttributes windowAttributes;
    windowAttributes.colormap = colormap;
    windowAttributes.event_mask = ExposureMask | KeyPressMask;

    // Create the window
    Window window = XCreateWindow(display, root, 0, 0, WIDTH, HEIGHT, 0, visual->depth, InputOutput, visual->visual,
                                   CWColormap | CWEventMask, &windowAttributes);

    // Set the window title
    XStoreName(display, window, "OpenGL Pixel Read");

    // Show the window
    XMapWindow(display, window);

    // Create an OpenGL context
    GLXContext glContext = glXCreateContext(display, visual, nullptr, GL_TRUE);
    glXMakeCurrent(display, window, glContext);

    // Set the viewport
    glViewport(0, 0, WIDTH, HEIGHT);

    // Vertex data for a triangle
    float vertices[] = {
        -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
         0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
         0.0f,  0.5f, 0.0f, 0.0f, 0.0f, 1.0f
    };

    // Main loop
    bool running = true;
    while (running) {
        // Handle events
        XEvent event;
        while (XPending(display)) {
            XNextEvent(display, &event);
            if (event.type == KeyPress) {
                running = false;
            }
        }

        // Clear the screen
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        // Draw the triangle
        glBegin(GL_TRIANGLES);
        glColor3f(1.0f, 0.0f, 0.0f);
        glVertex3f(vertices[0], vertices[1], vertices[2]);
        glColor3f(0.0f, 1.0f, 0.0f);
        glVertex3f(vertices[6], vertices[7], vertices[8]);
        glColor3f(0.0f, 0.0f, 1.0f);
        glVertex3f(vertices[12], vertices[13], vertices[14]);
        glEnd();

        // Swap buffers
        glXSwapBuffers(display, window);

        // Read pixels into a matrix
        std::vector<unsigned char> pixelData(WIDTH * HEIGHT * 3);
        readPixelsToMatrix(pixelData, WIDTH, HEIGHT);

        // (Optional) Process the pixel data here if needed
    }

    // Clean up
    glXMakeCurrent(display, None, nullptr);
    glXDestroyContext(display, glContext);
    XDestroyWindow(display, window);
    XCloseDisplay(display);

    return 0;
}

