#define _GNU_SOURCE
#include <EGL/egl.h>
#include <dlfcn.h>
#include <pthread.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Some drivers expose EGL_EXT_create_context_robustness, which wlroots
// consumes to request EGL_LOSE_CONTEXT_ON_RESET_EXT. Monado rejects sharing
// contexts with mismatched reset notification strategies, so hide that
// extension from wlroots by overriding eglQueryString.

typedef const char *(*eglQueryStringFn)(EGLDisplay display, EGLint name);

static const char *strip_extension(const char *exts, const char *target)
{
    if (!exts || !target || *target == '\0') {
        return exts;
    }

    size_t target_len = strlen(target);
    const char *found = strstr(exts, target);
    if (!found) {
        return exts;
    }

    char *copy = strdup(exts);
    if (!copy) {
        return exts;
    }

    char *start = strstr(copy, target);
    while (start) {
        char *end = start + target_len;

        // Trim leading spaces before the target substring.
        while (start > copy && start[-1] == ' ') {
            start--;
        }

        // Skip trailing spaces after the target substring.
        while (*end == ' ') {
            end++;
        }

        memmove(start, end, strlen(end) + 1);
        start = strstr(start, target);
    }

    // Collapse duplicate spaces introduced by removals.
    char *dst = copy;
    bool prev_space = false;
    for (char *src = copy; *src; ++src) {
        if (*src == ' ') {
            if (prev_space) {
                continue;
            }
            prev_space = true;
        } else {
            prev_space = false;
        }
        *dst++ = *src;
    }
    // Trim any trailing space left at the end.
    if (dst > copy && dst[-1] == ' ') {
        --dst;
    }
    *dst = '\0';

    return copy;
}

const char *eglQueryString(EGLDisplay display, EGLint name)
{
    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    static eglQueryStringFn real_eglQueryString = NULL;
    static const char *cached_extensions = NULL;

    if (!real_eglQueryString) {
        real_eglQueryString = (eglQueryStringFn)dlsym(RTLD_NEXT, "eglQueryString");
        if (!real_eglQueryString) {
            fprintf(stderr, "lunarwm: failed to resolve real eglQueryString\n");
            return NULL;
        }
    }

    const char *result = real_eglQueryString(display, name);
    if (name != EGL_EXTENSIONS || result == NULL) {
        return result;
    }

    pthread_mutex_lock(&mutex);
    if (cached_extensions == NULL) {
        cached_extensions = strip_extension(result, "EGL_EXT_create_context_robustness");
        if (cached_extensions == result) {
            cached_extensions = strdup(result);
        }
    }
    const char *filtered = cached_extensions;
    pthread_mutex_unlock(&mutex);

    return filtered;
}
