// MobileGL - MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp
// Copyright (c) 2025-2026 MobileGL-Dev
// Licensed under the GNU Lesser General Public License v3.0:
//   https://www.gnu.org/licenses/gpl-3.0.txt
//   https://www.gnu.org/licenses/lgpl-3.0.txt
// SPDX-License-Identifier: LGPL-3.0-only
// End of Source File Header

#include "EGLImpl.h"
#include "../GetProcAddress.h"
#include <Init.h>
#include <MG_Backend/BackendObjects.h>
#include <MG_State/EGLState/Core.h>
#include <mutex>
#include <sstream>
#include <type_traits>

namespace MobileGL::MG_Impl::EGLImpl {
    namespace {
        using EGLStateContext = MG_State::EGLState::EGLContext;

        EGLStateContext* GetState() {
            if (!MG_State::pEGLContext) {
                MGLOG_E_ONCE("pEGLContext is null. MG_State may not be initialized.");
            }
            return MG_State::pEGLContext.get();
        }

        // Entry points that can legitimately be an application's FIRST EGL
        // call (display/proc-address/string queries) lazily bring MobileGL
        // up here, so the library needs no static constructor and can
        // re-initialize after the last eglTerminate tore everything down.
        // Teardown-ish entry points keep using GetState() and fail benignly
        // when MobileGL is not initialized.
        EGLStateContext* GetStateEnsureInitialized() {
            MobileGL::EnsureInitialized();
            return GetState();
        }

        MG_Backend::BackendObject* GetBackendObject(EGLStateContext* state) {
            auto* backendObject = MG_Backend::pActiveBackendObject.get();
            if (!backendObject && state) {
                state->SetError(EGL_NOT_INITIALIZED);
            }
            return backendObject;
        }

        std::recursive_mutex& EGLOperationMutex() {
            static std::recursive_mutex mutex;
            return mutex;
        }

        String CurrentThreadIdString() {
            std::ostringstream stream;
            stream << std::this_thread::get_id();
            return stream.str();
        }

        MG_Backend::WindowBackend DetectWindowBackend() {
#if defined(ANDROID) || defined(__ANDROID__)
            return MG_Backend::WindowBackend::Android;
#elif defined(__APPLE__)
            return MG_Backend::WindowBackend::MetalLayer;
#elif defined(_WIN32)
            return MG_Backend::WindowBackend::Win32;
#elif defined(__linux__)
            return MG_Backend::WindowBackend::X11;
#else
            return MG_Backend::WindowBackend::Unknown;
#endif
        }

        EGLint GetAttribValue(const EGLint* attribList, EGLint attrib, EGLint defaultValue) {
            if (!attribList) {
                return defaultValue;
            }
            for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
                if (attribList[i] == attrib) {
                    return attribList[i + 1];
                }
            }
            return defaultValue;
        }

        EGLint GetAttribValueAttrib(const EGLAttrib* attribList, EGLint attrib, EGLint defaultValue) {
            if (!attribList) {
                return defaultValue;
            }
            for (SizeT i = 0; attribList[i] != EGL_NONE; i += 2) {
                if (attribList[i] == attrib) {
                    return static_cast<EGLint>(attribList[i + 1]);
                }
            }
            return defaultValue;
        }

        template <typename NativeType>
        Bool IsNullNativeHandle(NativeType nativeHandle) {
            if constexpr (std::is_pointer_v<NativeType>) {
                return nativeHandle == nullptr;
            } else {
                return nativeHandle == 0;
            }
        }

        template <typename NativeType>
        void* ToVoidHandle(NativeType nativeHandle) {
            if constexpr (std::is_pointer_v<NativeType>) {
                return reinterpret_cast<void*>(nativeHandle);
            } else {
                return reinterpret_cast<void*>(static_cast<SizeT>(nativeHandle));
            }
        }
    } // namespace

    EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, NativeWindowType window,
                                   const EGLint* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        if (!state->IsDisplayInitialized(dpy)) {
            state->SetError(EGL_NOT_INITIALIZED);
            return EGL_NO_SURFACE;
        }
        if (!state->ValidateConfigOnDisplay(dpy, config)) {
            state->SetError(EGL_BAD_CONFIG);
            return EGL_NO_SURFACE;
        }
        if (IsNullNativeHandle(window)) {
            state->SetError(EGL_BAD_NATIVE_WINDOW);
            return EGL_NO_SURFACE;
        }

        const MG_Backend::WindowHandle windowHandle = {
            .Backend = DetectWindowBackend(),
            .Handle = ToVoidHandle(window),
            .Width = static_cast<Uint32>(std::max<EGLint>(GetAttribValue(attrib_list, EGL_WIDTH, 0), 0)),
            .Height = static_cast<Uint32>(std::max<EGLint>(GetAttribValue(attrib_list, EGL_HEIGHT, 0), 0)),
        };

        EGLSurface surface = state->CreateWindowSurface(dpy, config, window, attrib_list);
        if (surface == EGL_NO_SURFACE) {
            return EGL_NO_SURFACE;
        }

        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            MGLOG_E_ONCE("activeBackendObject not initialized!");
            state->DestroySurface(dpy, surface);
            return EGL_NO_SURFACE;
        }
        if (!backendObject->CreateEGLWindowSurface(surface, windowHandle)) {
            state->DestroySurface(dpy, surface);
            state->SetError(EGL_BAD_NATIVE_WINDOW);
            return EGL_NO_SURFACE;
        }

        return surface;
    }

    EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface draw) {
        const std::lock_guard<std::recursive_mutex> operationLock(EGLOperationMutex());
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->ValidateSurfaceOnDisplay(dpy, draw)) {
            state->SetError(EGL_BAD_SURFACE);
            return EGL_FALSE;
        }

        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            MGLOG_E_ONCE("activeBackendObject not initialized!");
            return EGL_FALSE;
        }
        if (!backendObject->SwapEGLBuffers(dpy, draw)) {
            MGLOG_E_ONCE("eglSwapBuffers failed on thread=%s dpy=%p draw=%p", CurrentThreadIdString().c_str(), dpy, draw);
            state->SetError(EGL_BAD_SURFACE);
            return EGL_FALSE;
        }
        return EGL_TRUE;
    }

    EGLBoolean ChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size,
                            EGLint* num_config) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->ChooseConfig(dpy, attrib_list, configs, config_size, num_config) ? EGL_TRUE : EGL_FALSE;
    }

    EGLContext CreateContext(EGLDisplay dpy, EGLConfig config, EGLContext shareCtx, const EGLint* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_CONTEXT;
        }
        return state->CreateContext(dpy, config, shareCtx, attrib_list);
    }

    EGLBoolean Initialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
        auto* state = GetStateEnsureInitialized();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->InitializeDisplay(dpy, major, minor)) {
            return EGL_FALSE;
        }

        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            MGLOG_E_ONCE("activeBackendObject not initialized!");
            return EGL_FALSE;
        }
        if (!backendObject->InitializeEGLDisplay(dpy, major, minor)) {
            state->SetError(EGL_NOT_INITIALIZED);
            return EGL_FALSE;
        }
        return EGL_TRUE;
    }

    EGLDisplay GetDisplay(NativeDisplayType display) {
        auto* state = GetStateEnsureInitialized();
        if (!state) {
            return EGL_NO_DISPLAY;
        }
        return state->GetDisplay(display);
    }

    EGLint GetError() {
        auto* state = GetState();
        if (!state) {
            return EGL_NOT_INITIALIZED;
        }
        return state->ConsumeError();
    }

    EGLBoolean MakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
        const std::lock_guard<std::recursive_mutex> operationLock(EGLOperationMutex());
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }

        const auto oldDisplay = state->GetCurrentDisplay();
        const auto oldDraw = state->GetCurrentSurface(EGL_DRAW);
        const auto oldRead = state->GetCurrentSurface(EGL_READ);
        const auto oldContext = state->GetCurrentContext();
        const String threadId = CurrentThreadIdString();

        MGLOG_D("eglMakeCurrent begin thread=%s dpy=%p draw=%p read=%p ctx=%p oldDpy=%p oldDraw=%p oldRead=%p oldCtx=%p",
                threadId.c_str(), dpy, draw, read, ctx, oldDisplay, oldDraw, oldRead, oldContext);

        if (!state->MakeCurrent(dpy, draw, read, ctx)) {
            const EGLint error = state->ConsumeError();
            MGLOG_D("eglMakeCurrent rejected by EGLState thread=%s error=0x%04x", threadId.c_str(), error);
            state->SetError(error);
            return EGL_FALSE;
        }

        const Bool releaseCurrentRequest =
            draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT;
        if (releaseCurrentRequest) {
            if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
                if (!backendObject->MakeEGLCurrent(dpy, draw, read, ctx)) {
                    MGLOG_E_ONCE("eglMakeCurrent release failed in backend thread=%s", threadId.c_str());
                    state->MakeCurrent(oldDisplay, oldDraw, oldRead, oldContext);
                    state->SetError(EGL_BAD_ACCESS);
                    return EGL_FALSE;
                }
            }
            MGLOG_D("eglMakeCurrent release succeeded thread=%s", threadId.c_str());
            return EGL_TRUE;
        }

        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            MGLOG_E_ONCE("activeBackendObject not initialized!");
            state->MakeCurrent(oldDisplay, oldDraw, oldRead, oldContext);
            return EGL_FALSE;
        }
        if (!backendObject->MakeEGLCurrent(dpy, draw, read, ctx)) {
            MGLOG_E_ONCE("eglMakeCurrent backend attach failed thread=%s dpy=%p draw=%p read=%p ctx=%p", threadId.c_str(),
                    dpy, draw, read, ctx);
            state->SetError(EGL_BAD_ACCESS);
            state->MakeCurrent(oldDisplay, oldDraw, oldRead, oldContext);
            return EGL_FALSE;
        }
        MGLOG_D("eglMakeCurrent attach succeeded thread=%s dpy=%p draw=%p read=%p ctx=%p", threadId.c_str(), dpy, draw,
                read, ctx);
        return EGL_TRUE;
    }

    EGLBoolean DestroyContext(EGLDisplay dpy, EGLContext ctx) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->DestroyContext(dpy, ctx) ? EGL_TRUE : EGL_FALSE;
    }

    EGLBoolean DestroySurface(EGLDisplay dpy, EGLSurface surface) {
        const std::lock_guard<std::recursive_mutex> operationLock(EGLOperationMutex());
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->DestroySurface(dpy, surface)) {
            return EGL_FALSE;
        }
        if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
            backendObject->ReleaseEGLSurface(surface);
        }
        return EGL_TRUE;
    }

    EGLBoolean Terminate(EGLDisplay dpy) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->TerminateDisplay(dpy)) {
            return EGL_FALSE;
        }
        if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
            backendObject->ReleaseEGLResources();
        }
        // The last initialized display is gone and nothing is current on any
        // thread: tear the whole library down deterministically inside the
        // EGL lifecycle (backend, GL/EGL state, glslang). A later EGL call
        // re-initializes lazily via GetStateEnsureInitialized(); process exit
        // then has nothing left to destroy.
        if (!state->HasAnyInitializedDisplay() && !state->HasAnyCurrentContext()) {
            MobileGL::Destroy();
        }
        return EGL_TRUE;
    }

    EGLBoolean ReleaseThread() {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
            (void)backendObject->MakeEGLCurrent(EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
        }
        state->ReleaseThread();
        return EGL_TRUE;
    }

    EGLContext GetCurrentContext() {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_CONTEXT;
        }
        return state->GetCurrentContext();
    }

    EGLBoolean GetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->GetConfigAttrib(dpy, config, attribute, value) ? EGL_TRUE : EGL_FALSE;
    }

    EGLBoolean BindAPI(EGLenum api) {
        auto* state = GetStateEnsureInitialized();
        if (!state) {
            return EGL_FALSE;
        }
        switch (api) {
        case EGL_OPENGL_API:
        case EGL_OPENGL_ES_API:
        case EGL_OPENVG_API:
            state->SetBoundAPI(api);
            return EGL_TRUE;
        default:
            state->SetError(EGL_BAD_PARAMETER);
            return EGL_FALSE;
        }
    }

    EGLSurface GetCurrentSurface(EGLint readdraw) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        return state->GetCurrentSurface(readdraw);
    }

    EGLBoolean QuerySurface(EGLDisplay display, EGLSurface surface, EGLint attribute, EGLint* value) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->QuerySurface(display, surface, attribute, value) ? EGL_TRUE : EGL_FALSE;
    }

    char const* QueryString(EGLDisplay display, EGLint name) {
        auto* state = GetStateEnsureInitialized();
        if (!state) {
            return nullptr;
        }

        if (display != EGL_NO_DISPLAY && !state->ValidateDisplay(display)) {
            state->SetError(EGL_BAD_DISPLAY);
            return nullptr;
        }

        switch (name) {
        case EGL_VENDOR:
            return "MobileGL";
        case EGL_VERSION:
            return "1.5 MobileGL";
        case EGL_CLIENT_APIS:
            return "OpenGL OpenGL_ES";
        case EGL_EXTENSIONS:
            if (display == EGL_NO_DISPLAY) {
                return "EGL_EXT_client_extensions "
                       "EGL_EXT_platform_base "
                       "EGL_KHR_platform_base "
                       "EGL_MESA_platform_surfaceless";
            }
            return "EGL_KHR_create_context "
                   "EGL_MESA_platform_surfaceless";
        default:
            state->SetError(EGL_BAD_PARAMETER);
            return nullptr;
        }
    }

    EGLBoolean SwapInterval(EGLDisplay dpy, EGLint interval) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->SwapInterval(dpy, interval)) {
            return EGL_FALSE;
        }
        // Forward the request to the backend's native presentation path; without this
        // the app's vsync setting only ever reaches MobileGL's shadow state and the
        // native surface stays at the driver default (interval 1 = always vsynced).
        auto* backendObject = GetBackendObject(state);
        if (backendObject) {
            backendObject->SetEGLSwapInterval(static_cast<Int>(interval));
        }
        return EGL_TRUE;
    }

    EGLSurface CreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        const EGLint width = GetAttribValue(attrib_list, EGL_WIDTH, 1);
        const EGLint height = GetAttribValue(attrib_list, EGL_HEIGHT, 1);
        EGLSurface surface = state->CreatePbufferSurface(dpy, config, attrib_list);
        if (surface == EGL_NO_SURFACE) {
            return EGL_NO_SURFACE;
        }

        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            return EGL_NO_SURFACE;
        }
        if (!backendObject->CreateEGLPbufferSurface(surface, width, height)) {
            state->DestroySurface(dpy, surface);
            state->SetError(EGL_BAD_ALLOC);
            return EGL_NO_SURFACE;
        }

        return surface;
    }

    EGLBoolean BindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
            state->SetError(EGL_BAD_SURFACE);
            return EGL_FALSE;
        }
        if (buffer != EGL_BACK_BUFFER) {
            state->SetError(EGL_BAD_PARAMETER);
            return EGL_FALSE;
        }
        return EGL_TRUE;
    }

    EGLBoolean ReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
            state->SetError(EGL_BAD_SURFACE);
            return EGL_FALSE;
        }
        if (buffer != EGL_BACK_BUFFER) {
            state->SetError(EGL_BAD_PARAMETER);
            return EGL_FALSE;
        }
        return EGL_TRUE;
    }

    EGLBoolean CopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
            state->SetError(EGL_BAD_SURFACE);
            return EGL_FALSE;
        }
        if (IsNullNativeHandle(target)) {
            state->SetError(EGL_BAD_NATIVE_PIXMAP);
            return EGL_FALSE;
        }
        return EGL_TRUE;
    }

    EGLSurface CreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config,
                                             const EGLint* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        return state->CreatePbufferFromClientBuffer(dpy, buftype, buffer, config, attrib_list);
    }

    EGLSurface CreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap,
                                   const EGLint* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        return state->CreatePixmapSurface(dpy, config, pixmap, attrib_list);
    }

    EGLBoolean GetConfigs(EGLDisplay dpy, EGLConfig* configs, EGLint config_size, EGLint* num_config) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->GetConfigs(dpy, configs, config_size, num_config) ? EGL_TRUE : EGL_FALSE;
    }

    EGLDisplay GetCurrentDisplay() {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_DISPLAY;
        }
        return state->GetCurrentDisplay();
    }

    EGLenum QueryAPI() {
        auto* state = GetState();
        if (!state) {
            return EGL_OPENGL_API;
        }
        return state->GetBoundAPI();
    }

    EGLBoolean QueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->QueryContext(dpy, ctx, attribute, value) ? EGL_TRUE : EGL_FALSE;
    }

    EGLBoolean SurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
        (void)value;

        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->ValidateSurfaceOnDisplay(dpy, surface)) {
            state->SetError(EGL_BAD_SURFACE);
            return EGL_FALSE;
        }

        switch (attribute) {
        case EGL_MIPMAP_LEVEL:
        case EGL_SWAP_BEHAVIOR:
        case EGL_TEXTURE_FORMAT:
        case EGL_TEXTURE_TARGET:
        case EGL_MIPMAP_TEXTURE:
            return EGL_TRUE;
        default:
            state->SetError(EGL_BAD_ATTRIBUTE);
            return EGL_FALSE;
        }
    }

    EGLBoolean WaitClient() {
        return EGL_TRUE;
    }

    EGLBoolean WaitGL() {
        return EGL_TRUE;
    }

    EGLBoolean WaitNative(EGLint engine) {
        (void)engine;
        return EGL_TRUE;
    }

    EGLSync CreateSync(EGLDisplay dpy, EGLenum type, const EGLAttrib* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SYNC;
        }
        return state->CreateSync(dpy, type, attrib_list);
    }

    EGLBoolean DestroySync(EGLDisplay dpy, EGLSync sync) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->DestroySync(dpy, sync) ? EGL_TRUE : EGL_FALSE;
    }

    EGLint ClientWaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->ClientWaitSync(dpy, sync, flags, timeout);
    }

    EGLBoolean GetSyncAttrib(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib* value) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->GetSyncAttrib(dpy, sync, attribute, value) ? EGL_TRUE : EGL_FALSE;
    }

    EGLImage CreateImage(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer,
                         const EGLAttrib* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_IMAGE;
        }
        return state->CreateImage(dpy, ctx, target, buffer, attrib_list);
    }

    EGLBoolean DestroyImage(EGLDisplay dpy, EGLImage image) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->DestroyImage(dpy, image) ? EGL_TRUE : EGL_FALSE;
    }

    EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list) {
        (void)attrib_list;

        auto* state = GetStateEnsureInitialized();
        if (!state) {
            return EGL_NO_DISPLAY;
        }
        return state->GetPlatformDisplay(platform, native_display);
    }

    EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window,
                                           const EGLAttrib* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        if (native_window == nullptr) {
            state->SetError(EGL_BAD_NATIVE_WINDOW);
            return EGL_NO_SURFACE;
        }
        if (!state->IsDisplayInitialized(dpy)) {
            state->SetError(EGL_NOT_INITIALIZED);
            return EGL_NO_SURFACE;
        }
        if (!state->ValidateConfigOnDisplay(dpy, config)) {
            state->SetError(EGL_BAD_CONFIG);
            return EGL_NO_SURFACE;
        }

        const MG_Backend::WindowHandle windowHandle = {
            .Backend = DetectWindowBackend(),
            .Handle = native_window,
            .Width = static_cast<Uint32>(std::max<EGLint>(GetAttribValueAttrib(attrib_list, EGL_WIDTH, 0), 0)),
            .Height = static_cast<Uint32>(std::max<EGLint>(GetAttribValueAttrib(attrib_list, EGL_HEIGHT, 0), 0)),
        };

        EGLSurface surface = state->CreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
        if (surface == EGL_NO_SURFACE) {
            return EGL_NO_SURFACE;
        }

        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            MGLOG_E_ONCE("activeBackendObject not initialized!");
            state->DestroySurface(dpy, surface);
            return EGL_NO_SURFACE;
        }
        if (!backendObject->CreateEGLWindowSurface(surface, windowHandle)) {
            state->DestroySurface(dpy, surface);
            state->SetError(EGL_BAD_NATIVE_WINDOW);
            return EGL_NO_SURFACE;
        }

        return surface;
    }

    EGLBoolean ResizePlatformWindowSurface(EGLDisplay dpy, EGLSurface surface, EGLint width, EGLint height) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        if (!state->ResizeSurface(dpy, surface, width, height)) {
            return EGL_FALSE;
        }
        auto* backendObject = GetBackendObject(state);
        if (!backendObject) {
            MGLOG_E_ONCE("activeBackendObject not initialized!");
            return EGL_FALSE;
        }
        width = std::max<EGLint>(width, 1);
        height = std::max<EGLint>(height, 1);
        if (!backendObject->ResizeEGLWindowSurface(surface, static_cast<Uint32>(width), static_cast<Uint32>(height))) {
            state->SetError(EGL_BAD_NATIVE_WINDOW);
            return EGL_FALSE;
        }
        return EGL_TRUE;
    }

    EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap,
                                           const EGLAttrib* attrib_list) {
        auto* state = GetState();
        if (!state) {
            return EGL_NO_SURFACE;
        }
        return state->CreatePlatformPixmapSurface(dpy, config, native_pixmap, attrib_list);
    }

    EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags) {
        auto* state = GetState();
        if (!state) {
            return EGL_FALSE;
        }
        return state->WaitSync(dpy, sync, flags) ? EGL_TRUE : EGL_FALSE;
    }

    __eglMustCastToProperFunctionPointerType GetProcAddress(const char* name) {
        if (!name) {
            return nullptr;
        }
        MobileGL::EnsureInitialized();

        MGLOG_D("eglGetProcAddress(%s)", name);
        void* proc = MG_Impl::GetProcAddress(name);
        if (!proc) {
            MGLOG_D("Failed to get function: %s", name);
            return nullptr;
        }
        return (__eglMustCastToProperFunctionPointerType)proc;
    }
} // namespace MobileGL::MG_Impl::EGLImpl
