#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xcomposite.h>
#include <GL/glx.h>

Display *dpy;
Window root_win;
Window comp_win;
int screen;
int screen_width, screen_height;

GLXContext glx_ctx;
GLXFBConfig fb_config;

Atom wm_delete_window;
Atom net_active_window;
Atom net_wm_state;
Atom net_wm_state_fullscreen;
Atom wm_state;
pid_t firefox_pid = -1;

// Структура для хранения информации об окнах
typedef struct ManagedWindow {
    Window id;
    Pixmap pixmap;
    int x, y, width, height;
    int mapped;
    struct ManagedWindow *next;
} ManagedWindow;

ManagedWindow *windows = NULL;

// -------------------------------------------------------------
// 1. Инициализация X11 и создание полноэкранного окна композитора
// -------------------------------------------------------------
void init_x11() {
    dpy = XOpenDisplay(NULL);
    if (!dpy) {
        fprintf(stderr, "Не могу открыть дисплей\n");
        exit(1);
    }
    screen = DefaultScreen(dpy);
    root_win = DefaultRootWindow(dpy);
    screen_width = WidthOfScreen(DefaultScreenOfDisplay(dpy));
    screen_height = HeightOfScreen(DefaultScreenOfDisplay(dpy));

    int event_base, error_base;
    if (!XCompositeQueryExtension(dpy, &event_base, &error_base)) {
        fprintf(stderr, "Расширение Composite отсутствует\n");
        exit(1);
    }

    // Создаём своё собственное окно на весь экран
    XSetWindowAttributes attrs;
    attrs.override_redirect = True;
    attrs.background_pixel = 0;
    attrs.border_pixel = 0;
    attrs.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask |
                      SubstructureNotifyMask | SubstructureRedirectMask;

    comp_win = XCreateWindow(dpy, root_win,
                             0, 0, screen_width, screen_height, 0,
                             CopyFromParent, InputOutput, CopyFromParent,
                             CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWEventMask,
                             &attrs);

    // Устанавливаем свойства для оконного менеджера
    net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
    net_wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
    net_active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
    wm_state = XInternAtom(dpy, "WM_STATE", False);

    // Регистрируемся как оконный менеджер
    Atom wm_s0 = XInternAtom(dpy, "WM_S0", False);
    XSetSelectionOwner(dpy, wm_s0, comp_win, CurrentTime);

    // Делаем окно композитора полноэкранным и поверх всех
    XChangeProperty(dpy, comp_win, net_wm_state, XA_ATOM, 32,
                    PropModeReplace, (unsigned char *)&net_wm_state_fullscreen, 1);

    wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
    XSetWMProtocols(dpy, comp_win, &wm_delete_window, 1);

    XMapWindow(dpy, comp_win);
    XRaiseWindow(dpy, comp_win);

    // Скрываем курсор
    Cursor invisible_cursor;
    Pixmap bitmap = XCreateBitmapFromData(dpy, comp_win, "", 1, 1);
    XColor color = {0, 0, 0, 0, 0, 0};
    invisible_cursor = XCreatePixmapCursor(dpy, bitmap, bitmap, &color, &color, 0, 0);
    XDefineCursor(dpy, comp_win, invisible_cursor);
    XFreePixmap(dpy, bitmap);

    XFlush(dpy);

    printf("Окно композитора создано: 0x%lx (%dx%d) полноэкранный режим\n",
           comp_win, screen_width, screen_height);
}

// -------------------------------------------------------------
// 2. Инициализация GLX
// -------------------------------------------------------------
void init_glx() {
    XWindowAttributes win_attrs;
    XGetWindowAttributes(dpy, comp_win, &win_attrs);

    int fb_attribs[] = {
        GLX_RENDER_TYPE,   GLX_RGBA_BIT,
        GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
        GLX_RED_SIZE,      8,
        GLX_GREEN_SIZE,    8,
        GLX_BLUE_SIZE,     8,
        GLX_DOUBLEBUFFER,  True,
        None
    };

    int num_fb;
    GLXFBConfig *fb_configs = glXChooseFBConfig(dpy, screen, fb_attribs, &num_fb);
    if (!fb_configs || num_fb == 0) {
        fprintf(stderr, "Не удалось получить FBConfig\n");
        exit(1);
    }

    fb_config = fb_configs[0];
    XFree(fb_configs);

    glx_ctx = glXCreateNewContext(dpy, fb_config, GLX_RGBA_TYPE, NULL, True);
    if (!glx_ctx) {
        fprintf(stderr, "Не удалось создать GLX-контекст\n");
        exit(1);
    }

    if (!glXMakeCurrent(dpy, comp_win, glx_ctx)) {
        fprintf(stderr, "Не удалось сделать контекст текущим\n");
        exit(1);
    }

    printf("GLX инициализирован. OpenGL: %s\n", glGetString(GL_VERSION));
}

// -------------------------------------------------------------
// 3. Запуск Firefox
// -------------------------------------------------------------
void start_firefox() {
    firefox_pid = fork();

    if (firefox_pid == -1) {
        perror("fork");
        return;
    }

    if (firefox_pid == 0) {
        // Даем время на инициализацию
        sleep(1);

        // Запускаем Firefox с параметрами для правильного отображения
        execlp("firefox", "firefox",
               "-kiosk", "about:blank",
               "-width", "800", "-height", "600",
               NULL);

        perror("execlp");
        exit(1);
    }

    printf("Firefox запущен с PID: %d\n", firefox_pid);
}

// -------------------------------------------------------------
// 4. Управление окнами
// -------------------------------------------------------------
void maximize_window(Window win) {
    // Отправляем событие ConfigureRequest для максимизации окна
    XEvent ev;

    ev.xconfigurerequest.type = ConfigureRequest;
    ev.xconfigurerequest.display = dpy;
    ev.xconfigurerequest.window = win;
    //ev.xconfigurerequest.root = root_win;
    ev.xconfigurerequest.x = 0;
    ev.xconfigurerequest.y = 0;
    ev.xconfigurerequest.width = screen_width;
    ev.xconfigurerequest.height = screen_height;
    ev.xconfigurerequest.border_width = 0;
    ev.xconfigurerequest.above = None;
    ev.xconfigurerequest.detail = Above;
    ev.xconfigurerequest.value_mask = CWX | CWY | CWWidth | CWHeight | CWBorderWidth;

    XSendEvent(dpy, root_win, False, SubstructureRedirectMask | SubstructureNotifyMask, &ev);
    XFlush(dpy);

    printf("Отправлена команда максимизации для окна 0x%lx\n", win);
}

void add_window(Window win) {
    // Проверяем, не окно ли это композитора
    if (win == comp_win) return;

    // Проверяем, не отслеживаем ли уже
    ManagedWindow *current = windows;
    while (current) {
        if (current->id == win) return;
        current = current->next;
    }

    // Получаем атрибуты окна
    XWindowAttributes attrs;
    if (!XGetWindowAttributes(dpy, win, &attrs)) {
        return;
    }

    // Игнорируем окна без карты
    if (attrs.map_state != IsViewable) {
        return;
    }

    // Включаем композитный режим
    XCompositeRedirectWindow(dpy, win, CompositeRedirectAutomatic);

    // Получаем Pixmap
    Pixmap pixmap = XCompositeNameWindowPixmap(dpy, win);
    if (!pixmap) {
        printf("Не удалось получить pixmap для окна 0x%lx\n", win);
        return;
    }

    // Добавляем в список
    ManagedWindow *new_win = malloc(sizeof(ManagedWindow));
    new_win->id = win;
    new_win->pixmap = pixmap;
    new_win->x = attrs.x;
    new_win->y = attrs.y;
    new_win->width = attrs.width;
    new_win->height = attrs.height;
    new_win->mapped = 1;
    new_win->next = windows;
    windows = new_win;

    printf("Добавлено окно 0x%lx: размер %dx%d, позиция (%d,%d)\n",
           win, attrs.width, attrs.height, attrs.x, attrs.y);

    // Максимизируем окно, если это Firefox или другое приложение
    // Получаем имя окна для проверки
    char *window_name = NULL;
    XFetchName(dpy, win, &window_name);
    if (window_name) {
        printf("Имя окна: %s\n", window_name);
        XFree(window_name);
    }

    // Максимизируем все нормальные окна
    maximize_window(win);
}

void remove_window(Window win) {
    ManagedWindow **current = &windows;
    while (*current) {
        if ((*current)->id == win) {
            ManagedWindow *to_remove = *current;
            *current = (*current)->next;

            if (to_remove->pixmap) {
                XFreePixmap(dpy, to_remove->pixmap);
            }
            free(to_remove);

            printf("Удалено окно 0x%lx\n", win);
            return;
        }
        current = &(*current)->next;
    }
}

// -------------------------------------------------------------
// 5. Отрисовка
// -------------------------------------------------------------
void render_all_windows() {
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    ManagedWindow *current = windows;

    // Временное решение: рисуем цветные прямоугольники вместо текстур
    // Для реальной работы нужно использовать текстуры из pixmap
    while (current) {
        // Рисуем рамку окна
        glColor3f(0.3f, 0.5f, 0.8f);
        glBegin(GL_QUADS);
            glVertex2i(current->x, current->y);
            glVertex2i(current->x + current->width, current->y);
            glVertex2i(current->x + current->width, current->y + current->height);
            glVertex2i(current->x, current->y + current->height);
        glEnd();

        // Рисуем границу
        glColor3f(1.0f, 1.0f, 1.0f);
        glBegin(GL_LINE_LOOP);
            glVertex2i(current->x, current->y);
            glVertex2i(current->x + current->width, current->y);
            glVertex2i(current->x + current->width, current->y + current->height);
            glVertex2i(current->x, current->y + current->height);
        glEnd();

        current = current->next;
    }

    glXSwapBuffers(dpy, comp_win);
}

// -------------------------------------------------------------
// 6. Обработка событий
// -------------------------------------------------------------
void handle_map_request(XMapRequestEvent *ev) {
    printf("MapRequest для окна 0x%lx\n", ev->window);
    if (ev->window != comp_win) {
        XMapWindow(dpy, ev->window);
        add_window(ev->window);
    }
}

void handle_map_notify(XMapEvent *ev) {
    printf("MapNotify для окна 0x%lx\n", ev->window);
    if (ev->window != comp_win) {
        add_window(ev->window);
    }
}

void handle_unmap_notify(XUnmapEvent *ev) {
    printf("UnmapNotify для окна 0x%lx\n", ev->window);
    if (ev->window != comp_win) {
        remove_window(ev->window);
    }
}

void handle_configure_request(XConfigureRequestEvent *ev) {
    if (ev->window == comp_win) return;

    XWindowChanges changes;
    changes.x = ev->x;
    changes.y = ev->y;
    changes.width = ev->width;
    changes.height = ev->height;
    changes.border_width = ev->border_width;
    changes.sibling = ev->above;
    changes.stack_mode = ev->detail;

    // Принудительно устанавливаем полноэкранный режим для всех окон
    changes.width = screen_width;
    changes.height = screen_height;
    changes.x = 0;
    changes.y = 0;

    XConfigureWindow(dpy, ev->window,
                    CWX | CWY | CWWidth | CWHeight | CWBorderWidth |
                    (ev->value_mask & (CWSibling | CWStackMode)),
                    &changes);

    printf("ConfigureRequest для 0x%lx: установлен размер %dx%d\n",
           ev->window, screen_width, screen_height);
}

// -------------------------------------------------------------
// 7. Главный цикл
// -------------------------------------------------------------
void main_loop() {
    XEvent ev;

    // Подписываемся на события
    XSelectInput(dpy, root_win,
                SubstructureNotifyMask |
                SubstructureRedirectMask |
                PropertyChangeMask);

    // Запускаем Firefox
    start_firefox();

    printf("Композитор запущен. Нажмите Q для выхода.\n");
    printf("Размер экрана: %dx%d\n", screen_width, screen_height);

    // Первоначальная отрисовка
    render_all_windows();

    while (1) {
        XNextEvent(dpy, &ev);

        switch (ev.type) {
            case MapRequest:
                handle_map_request(&ev.xmaprequest);
                render_all_windows();
                break;

            case MapNotify:
                handle_map_notify(&ev.xmap);
                render_all_windows();
                break;

            case UnmapNotify:
                handle_unmap_notify(&ev.xunmap);
                render_all_windows();
                break;

            case ConfigureRequest:
                handle_configure_request(&ev.xconfigurerequest);
                render_all_windows();
                break;

            case Expose:
                if (ev.xexpose.count == 0) {
                    render_all_windows();
                }
                break;

            case KeyPress:
                if (ev.xkey.keycode == 24) { // Q
                    printf("Выход по Q\n");
                    return;
                }
                break;

            case ClientMessage:
                if ((Atom)ev.xclient.data.l[0] == wm_delete_window) {
                    printf("WM_DELETE_WINDOW\n");
                    return;
                }
                break;

            default:
                break;
        }
    }
}

// -------------------------------------------------------------
// 8. Очистка
// -------------------------------------------------------------
void cleanup() {
    // Удаляем все окна
    while (windows) {
        remove_window(windows->id);
    }

    glXMakeCurrent(dpy, None, NULL);
    if (glx_ctx) glXDestroyContext(dpy, glx_ctx);
    if (comp_win) XDestroyWindow(dpy, comp_win);
    if (dpy) XCloseDisplay(dpy);

    if (firefox_pid > 0) {
        kill(firefox_pid, SIGTERM);
        waitpid(firefox_pid, NULL, WNOHANG);
    }

    printf("Ресурсы освобождены\n");
}

// -------------------------------------------------------------
int main() {
    init_x11();
    init_glx();
    main_loop();
    cleanup();
    return 0;
}