// GLCanvas.cpp
#include "GLCanvas.h"
#include <algorithm>
#include <cstdio>
//#include <iostream>
#include <fstream>
#include <sstream>
#include <EGL/eglplatform.h>
#include <hilog/log.h>
#include <nlohmann/json.hpp>

#include "common/common.h"

using json = nlohmann::json;

GLCanvas::GLCanvas(std::shared_ptr<RNGLContext> rnglContext)
{
    // 构造函数：初始化成员变量
    this->rnglContext = rnglContext;
    //data = std::make_shared<GLData>();
    //renderData = std::make_shared<GLRenderData>();
}

GLCanvas::~GLCanvas()
{
    DestroyEGL(); // 析构时清理资源
}

bool GLCanvas::OnSurfaceCreated(OHNativeWindow* window) {
    imagesToPreload.clear();
    preloaded.clear();
    images.clear();
    contentTextures.clear();
    shaders.clear();
    fbos.clear();
    data = nullptr;
    renderData = nullptr;
    syncData();
    
    //std::lock_guard<std::mutex> lock(renderMutex_);
    return InitEGL(window); // 初始化 EGL
}

void GLCanvas::OnSurfaceChanged(int width, int height) {
    m_width = width;
    m_height = height;
}

bool GLCanvas::InitEGL(void* window)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "GLCanvas", "EglWindowInit execute");
    if (window == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "EglWindowInit: param error");
        return false;
    }

    m_eglWindow = static_cast<EGLNativeWindowType>(window);

    // Init display.
    m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (m_eglDisplay == EGL_NO_DISPLAY) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "EglWindowInit eglGetDisplay: unable to get EGL display");
        return false;
    }

    EGLint majorVersion;
    EGLint minorVersion;
    if (!eglInitialize(m_eglDisplay, &majorVersion, &minorVersion)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "EglWindowInit eglInitialize: unable to get initialize EGL display");
        return false;
    }

    // Select configuration.
    const EGLint maxConfigSize = 1;
    EGLint numConfigs;
    if (!eglChooseConfig(m_eglDisplay, ATTRIB_LIST, &m_eglConfig, maxConfigSize, &numConfigs)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "EglWindowInit eglChooseConfig: unable to choose configs");
        return false;
    }

    if (!CreateEnvironment()) {
        return false;
    }
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "GLCanvas", "InitEGL end");
    return true;
}

bool GLCanvas::CreateEnvironment() {
    // Create surface.
    if (m_eglWindow == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "eglWindow_ is null");
        return false;
    }
    // Create context.
    m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, CONTEXT_ATTRIBS);
    m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, NULL);
    if (m_eglSurface == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "eglCreateWindowSurface: unable to create surface");
        return false;
    }
    if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "eglMakeCurrent failed");
        return false;
    }

    return true;
}

void GLCanvas::DrawFrame()
{
    render();
}

void GLCanvas::UpdateSize(int width, int height) {
    m_width = width;
    m_height = height;
}

void GLCanvas::SetRNGLContext(std::shared_ptr<RNGLContext> rnglContext) {
    this->rnglContext = rnglContext;
}

void GLCanvas::SetData(const std::string& data) {
    this->data = DealData(data);
    syncData();
    render();
}

std::shared_ptr<GLData> GLCanvas::DealData(const std::string& jsonData) {
    if (jsonData.empty()) return nullptr;
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "GLCanvas", "DealData: jsonData = %{public}s", jsonData.c_str());
    json uniforms = json::parse(jsonData.c_str());
    
    std::vector<std::shared_ptr<GLData>> contextChildren;
    if (uniforms.contains("contextChildren")) {
        for (const auto& child : uniforms["contextChildren"]) {
            auto node = DealData(child.get<std::string>());
            contextChildren.push_back(node);
        }
    }
    std::vector<std::shared_ptr<GLData>> children;
    if (uniforms.contains("children")) {
        for (const auto& child : uniforms["children"]) {
            //OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "GLCanvas", "DealData: children = %{public}s", child.dump().c_str());
            auto node = DealData(child.dump());
            children.push_back(node);
        }
    }
    
    auto glData = std::make_shared<GLData>();
    if (uniforms.contains("shader")) {
        glData->shader = uniforms["shader"].get<int>();
    }
    if (uniforms.contains("uniforms")) {
        glData->uniforms = uniforms["uniforms"].dump();
    }
    if (uniforms.contains("width")) {
        glData->width = uniforms["width"].get<double>();
    }
    if (uniforms.contains("height")) {
        glData->height = uniforms["height"].get<double>();
    }
    if (uniforms.contains("pixelRatio")) {
        glData->pixelRatio = uniforms["pixelRatio"].get<double>();
    }
    if (uniforms.contains("fboId")) {
        glData->fboId = uniforms["fboId"].get<int>();
    }
    
    glData->contextChildren = contextChildren;
    glData->children = children;
    
    return glData;
}

void GLCanvas::DestroyEGL() {
    if ((m_eglDisplay == nullptr) || (m_eglSurface == nullptr) || (!eglDestroySurface(m_eglDisplay, m_eglSurface))) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "Release eglDestroySurface failed");
    }

    if ((m_eglDisplay == nullptr) || (m_eglContext == nullptr) || (!eglDestroyContext(m_eglDisplay, m_eglContext))) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "Release eglDestroyContext failed");
    }

    if ((m_eglDisplay == nullptr) || (!eglTerminate(m_eglDisplay))) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "Release eglTerminate failed");
    }
}

void GLCanvas::AddImageData(const std::string& src, std::shared_ptr<ImageData>& data) {
    OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "GLCanvas", "AddImageData: src = %{public}s", src.c_str());
    if (imagesData.find(src) == imagesData.end()) {
        imagesData[src] = data;
    }
}

void GLCanvas::CaptureFrame(const std::string& filePath) {
    capture(filePath);
}

void GLCanvas::resizeUniformContentTextures(int n) {
    int length = contentTextures.size();
    if (length == n) return;
    if (n < length) {
        contentTextures.resize(n);
    }
    else {
        for (int i = contentTextures.size(); i < n; i++) {
            contentTextures.emplace_back(std::make_shared<GLTexture>());
        }
    }
}

std::shared_ptr<GLFBO> GLCanvas::GetFBO(int& id) {
    if (fbos.find(id) == fbos.end()) {
        fbos[id] = std::make_shared<GLFBO>();
    }
    return fbos[id];
}

std::shared_ptr<GLShader> GLCanvas::GetShader(int& id) {
    auto it = shaders.find(id);
    if (it == shaders.end()) {
        auto shaderData = rnglContext->GetShaderData(id);
        if (!shaderData) {
            return nullptr;
        }
        auto newShader = std::make_shared<GLShader>(shaderData, id, rnglContext);
        shaders[id] = newShader;
        return newShader;
    }
    return it->second;
}

int GLCanvas::CountPreloaded() {
    int nb = 0;
    for (const auto& toload : imagesToPreload) {
        if (std::find(preloaded.begin(), preloaded.end(), toload) != preloaded.end()) {
            nb++;
        }
    }
    return nb;
}

std::shared_ptr<OnProgressData> GLCanvas::GetOnProgressData() {
    int count = CountPreloaded();
    int total = imagesToPreload.size();
    double progress = static_cast<double>(count) / static_cast<double>(total);
    auto progressData = std::make_shared<OnProgressData>(count, total, progress);
    return progressData;
}

EGLContext GLCanvas::GetEGLContext() {
    return m_eglContext;
}

void GLCanvas::onImageLoad(const std::string& loaded) {
    preloaded.push_back(loaded);
    imagesToPreload.push_back(loaded);
    dirtyOnLoad = true;
}

std::shared_ptr<GLRenderData> GLCanvas::recSyncData(const std::shared_ptr<GLData> data, std::unordered_map<std::string, std::shared_ptr<GLImage>>& newImages) {
    if (!data) return nullptr;
    // 保存之前的图像映射
    std::unordered_map<std::string, std::shared_ptr<GLImage>> prevImages = images;

    // 获取着色器
    auto shader = GetShader(data->shader);
    if (!shader || !shader->ensureCompile()) {
        return nullptr;
    }

    // 初始化各种统一变量映射
    std::unordered_map<std::string, GLint> uniformsInteger;
    std::unordered_map<std::string, GLfloat> uniformsFloat;
    std::unordered_map<std::string, std::vector<GLint>> uniformsIntBuffer;
    std::unordered_map<std::string, std::vector<GLfloat>> uniformsFloatBuffer;
    std::unordered_map<std::string, std::shared_ptr<GLTexture>> textures;

    // 递归处理子节点
    std::vector<std::shared_ptr<GLRenderData>> contextChildren;
    for (const auto& child : data->contextChildren) {
        auto node = recSyncData(child, newImages);
        if (!node) {
            return nullptr;
        }
        contextChildren.push_back(std::move(node));
    }

    std::vector<std::shared_ptr<GLRenderData>> children;
    for (const auto& child : data->children) {
        auto node = recSyncData(child, newImages);
        if (!node) {
            return nullptr;
        }
        children.push_back(std::move(node));
    }

    if (data->uniforms.empty()) {
        return nullptr;
    }

    // 获取着色器的统一变量信息
    std::unordered_map<std::string, int> uniformTypes = shader->getUniformTypes();
    std::vector<std::string> uniformNames = shader->getUniformNames();
    std::unordered_map<std::string, int> uniformSizes = shader->getUniformSizes();

    json uniforms = json::parse(data->uniforms);
    int units = 0;
    // 遍历统一变量
    for (const auto uniform : uniforms.items()) {
        std::string uniformName = uniform.key();
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "GLCanvas", "recSyncData: uniformName = %{public}s", uniformName.c_str());
        auto value = uniform.value();
        if (uniformTypes.find(uniformName) == uniformTypes.end()) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "recSyncData: uniformTypes not uniformName: %{public}s", uniformName.c_str());
            break;
        }
        if (uniformSizes.find(uniformName) == uniformSizes.end()) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GLCanvas", "recSyncData: uniformSizes not uniformName: %{public}s", uniformName.c_str());
            break;
        }
        int type = uniformTypes.at(uniformName);
        int size = uniformSizes.at(uniformName);

        if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE) {
            uniformsInteger[uniformName] = units++;

            if (value.empty()) {
                auto emptyTexture = std::make_shared<GLTexture>();
                emptyTexture->setPixelsEmpty();
                textures[uniformName] = emptyTexture;
            } else {
                if (value.contains("type")) {
                    std::string t = value["type"].get<std::string>();
                    if (t == "content") {
                        int id = value["id"].get<int>();
                        if (id >= static_cast<int>(contentTextures.size())) {
                            resizeUniformContentTextures(id + 1);
                        }
                        //textures[uniformName] = std::make_shared<GLTexture>(contentTextures[id]);
                        textures[uniformName] = contentTextures[id];
                    } else if (t == "fbo") {
                        int id = value["id"].get<int>();
                        auto fbo = GetFBO(id);
                        textures[uniformName] = fbo->color[0];
                    } else if (t == "uri") {
                        std::string src = "";
                        bool isStatic = value.contains("isStatic") && value["isStatic"].get<bool>();
                        if (value.contains("path")) src = value["path"].get<std::string>();
                        if (src.empty() || (isStatic && value.contains("uri"))) src = value["uri"].get<std::string>();
                        //src = resolveSrc(src);
                        if (src.empty()) {
                            shader->runtimeException("texture uniform '" + uniformName + "': Invalid uri format '" + value.dump() + "'");
                            return nullptr;
                        }

                        auto it = newImages.find(src);
                        if (it == newImages.end()) {
                            it = prevImages.find(src);
                            if (it != prevImages.end()) {
                                newImages[src] = it->second;
                            }
                        }
                        if (it == prevImages.end()) {
                            onImageLoad(src);
                            auto image = std::make_shared<GLImage>();
                            if (imagesData.find(src) != imagesData.end()) {
                                if (imagesData[src]->path.empty()) {
                                    image->setSrc(src, imagesData[src]->width, imagesData[src]->height, imagesData[src]->data);
                                } else {
                                    image->setSrc(imagesData[src]->path, imagesData[src]->width, imagesData[src]->height, imagesData[src]->data);
                                }
                            } else {
                                std::vector<unsigned char> vec;
                                image->setSrc(src, data->width, data->height, vec);
                            }
                            newImages[src] = image;
                            textures[uniformName] = image->getTexture();
                        } else {
                            textures[uniformName] = it->second->getTexture();
                        }
                    } else {
                        shader->runtimeException("texture uniform '" + uniformName + "': Unexpected type '" + std::to_string(type) + "'");
                        return nullptr;
                    }
                }
            }
        } else {
            if (size == 1) {
                switch (type) {
                    case GL_INT:
                        uniformsInteger[uniformName] = value.get<int>();
                        break;
                    case GL_BOOL:
                        uniformsInteger[uniformName] = value.get<bool>()? 1 : 0;
                        break;
                    case GL_FLOAT:
                        uniformsFloat[uniformName] = value.get<float>();
                        break;
                    case GL_FLOAT_VEC2:
                    case GL_FLOAT_VEC3:
                    case GL_FLOAT_VEC4:
                    case GL_FLOAT_MAT2:
                    case GL_FLOAT_MAT3:
                    case GL_FLOAT_MAT4: {
                        int arraySize = value.size();
                        if (arraySizeForType(type) != static_cast<int>(arraySize)) {
                            shader->runtimeException("uniform '" + uniformName + "': Invalid array size: " + std::to_string(arraySize) + ". Expected: " + std::to_string(arraySizeForType(type)));
                            return nullptr;
                        }
                        std::vector<float> buf(arraySize);
                        for (int i = 0; i < arraySize; ++i) {
                            buf[i] = value.at(i).get<float>();
                        }
                        uniformsFloatBuffer[uniformName] = buf;
                        break;
                    }
                    case GL_INT_VEC2:
                    case GL_INT_VEC3:
                    case GL_INT_VEC4:
                    case GL_BOOL_VEC2:
                    case GL_BOOL_VEC3:
                    case GL_BOOL_VEC4: {
                        int arraySize = value.size();
                        if (arraySizeForType(type) != static_cast<int>(arraySize)) {
                            shader->runtimeException("uniform '" + uniformName + "': Invalid array size: " + std::to_string(arraySize) + ". Expected: " + std::to_string(arraySizeForType(type)));
                            return nullptr;
                        }
                        std::vector<int> buf(arraySize);
                        for (int i = 0; i < arraySize; ++i) {
                            buf[i] = value.at(i).get<int>();
                        }
                        uniformsIntBuffer[uniformName] = buf;
                        break;
                    }
                    default:
                        shader->runtimeException("uniform '" + uniformName + "': type not supported: " + std::to_string(type));
                        return nullptr;
                }
            } else {
                if (size != static_cast<int>(value.size())) {
                    shader->runtimeException("uniform '" + uniformName + "': Invalid array size: " + std::to_string(value.size()) + ". Expected: " + std::to_string(size));
                    return nullptr;
                }
                for (int i = 0; i < size; ++i) {
                    std::string name = uniformName + "[" + std::to_string(i) + "]";
                    switch (type) {
                        case GL_INT:
                            uniformsInteger[name] = value.at(i).get<int>();
                            break;
                        case GL_BOOL:
                            uniformsInteger[name] = value.at(i).get<bool>() ? 1 : 0;
                            break;
                        case GL_FLOAT:
                            uniformsFloat[name] = value.at(i).get<float>();
                            break;
                        case GL_FLOAT_VEC2:
                        case GL_FLOAT_VEC3:
                        case GL_FLOAT_VEC4:
                        case GL_FLOAT_MAT2:
                        case GL_FLOAT_MAT3:
                        case GL_FLOAT_MAT4: {
                            auto arr = value.at(i);
                            if (arraySizeForType(type) != static_cast<int>(arr.size())) {
                                shader->runtimeException("uniform '" + name + "': Invalid array size: " + std::to_string(arr.size()) + ". Expected: " + std::to_string(arraySizeForType(type)));
                                return nullptr;
                            }
                            std::vector<float> buf(arr.size());
                            for (int j = 0; j < arr.size(); ++j) {
                                buf[j] = arr.at(j).get<float>();
                            }
                            uniformsFloatBuffer[name] = buf;
                            break;
                        }
                        case GL_INT_VEC2:
                        case GL_INT_VEC3:
                        case GL_INT_VEC4:
                        case GL_BOOL_VEC2:
                        case GL_BOOL_VEC3:
                        case GL_BOOL_VEC4: { 
                            auto arr = value.at(i);
                            if (arraySizeForType(type) != static_cast<int>(arr.size())) {
                                shader->runtimeException("uniform '" + name + "': Invalid array size: " + std::to_string(arr.size()) + ". Expected: " + std::to_string(arraySizeForType(type)));
                                return nullptr;
                            }
                            std::vector<int> buf(arr.size());
                            for (int j = 0; j < arr.size(); ++j) {
                                buf[j] = arr.at(j).get<int>();
                            }
                            uniformsIntBuffer[name] = buf;
                            break;
                        }
                        default:
                            shader->runtimeException("uniform '" + name + "': type not supported: " + std::to_string(type));
                            return nullptr;
                    }
                }
            }
        }
    }

    // 检查最大纹理单元数
    int maxTextureUnits;
    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
    if (units > maxTextureUnits) {
        shader->runtimeException("Maximum number of texture reach. got " + std::to_string(units) + " >= max " + std::to_string(maxTextureUnits));
        return nullptr;
    }

    // 检查所有定义的统一变量是否都已提供
    for (const auto& uniformName : uniformNames) {
        int size = uniformSizes.at(uniformName);
        if (size == 1) {
            if (uniformsFloat.find(uniformName) == uniformsFloat.end() &&
                uniformsInteger.find(uniformName) == uniformsInteger.end() &&
                uniformsFloatBuffer.find(uniformName) == uniformsFloatBuffer.end() &&
                uniformsIntBuffer.find(uniformName) == uniformsIntBuffer.end()) {
                shader->runtimeException("All defined uniforms must be provided. Missing '" + uniformName + "'");
                return nullptr;
            }
        } else {
            for (int i = 0; i < size; ++i) {
                std::string name = uniformName + "[" + std::to_string(i) + "]";
                if (uniformsFloat.find(name) == uniformsFloat.end() &&
                    uniformsInteger.find(name) == uniformsInteger.end() &&
                    uniformsFloatBuffer.find(name) == uniformsFloatBuffer.end() &&
                    uniformsIntBuffer.find(name) == uniformsIntBuffer.end()) {
                    shader->runtimeException("All defined uniforms must be provided. Missing '" + name + "'");
                    return nullptr;
                }
            }
        }
    }

    // 创建并返回 GLRenderData 对象
    auto renderData = std::make_shared<GLRenderData>(
        shader,
        uniformsInteger,
        uniformsFloat,
        uniformsIntBuffer,
        uniformsFloatBuffer,
        textures,
        static_cast<int>(data->width * data->pixelRatio),
        static_cast<int>(data->height * data->pixelRatio),
        data->fboId,
        std::move(contextChildren),
        std::move(children)
    );
    return renderData;
}

bool GLCanvas::syncData() {
    if (!data) return true;

    std::unordered_map<std::string, std::shared_ptr<GLImage>> newImages;
    auto node = recSyncData(data, newImages);
    if (!node) return false;

    std::set<std::string> oldImageKeys;
    for (const auto& pair : images) {
        oldImageKeys.insert(pair.first);
    }

    std::set<std::string> newImageKeys;
    for (const auto& pair : newImages) {
        newImageKeys.insert(pair.first);
    }

    std::set<std::string> imagesGone = diff(oldImageKeys, newImageKeys);

    images = std::move(newImages);

    // 移除 preloaded 中不在新 images 里的元素
    for (auto it = preloaded.begin(); it != preloaded.end(); ) {
        if (imagesGone.find(*it) != imagesGone.end()) {
            it = preloaded.erase(it);
        } else {
            ++it;
        }
    }

    renderData = std::move(node);
    return true;
}

void GLCanvas::recRender (const std::shared_ptr<GLRenderData>& renderData) {
    if (!renderData) return;
    
    for (const auto& child : renderData->contextChildren) {
        recRender(child);
    }

    for (const auto& child : renderData->children) {
        recRender(child);
    }

    if (renderData->fboId == -1) {
        OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "GLCanvas", "recRender: width = %{public}d height = %{public}d", renderData->width, renderData->height);
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO_);
        glViewport(0, 0, renderData->width, renderData->height);
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    } else {
        auto fbo = GetFBO(renderData->fboId);
        fbo->setShape(renderData->width, renderData->height);
        fbo->bind();
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

    renderData->shader->bind();

    for (const auto& texturePair : renderData->textures) {
        const std::string& uniformName = texturePair.first;
        auto texture = texturePair.second;
        int unit = renderData->uniformsInteger[uniformName];
        texture->bind(unit);
        renderData->shader->setUniform(uniformName, unit);
    }

    for (const auto& uniformPair : renderData->uniformsInteger) {
        const std::string& uniformName = uniformPair.first;
        int value = uniformPair.second;
        renderData->shader->setUniform(uniformName, value);
    }

    auto uniformTypes = renderData->shader->getUniformTypes();
    for (const auto& uniformPair : renderData->uniformsFloat) {
        const std::string& uniformName = uniformPair.first;
        float value = uniformPair.second;
        renderData->shader->setUniform(uniformName, value);
    }

    for (const auto& uniformPair : renderData->uniformsFloatBuffer) {
        const std::string& uniformName = uniformPair.first;
        auto value = uniformPair.second;
        renderData->shader->setUniform(uniformName, value.data(), uniformTypes[uniformName]);
    }

    for (const auto& uniformPair : renderData->uniformsIntBuffer) {
        const std::string& uniformName = uniformPair.first;
        auto value = uniformPair.second;
        renderData->shader->setUniform(uniformName, value.data(), uniformTypes[uniformName]);
    }

//    GLfloat value= 0.5;
//    renderData->shader->setUniform("blue", value);
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    eglSwapBuffers(m_eglDisplay, m_eglSurface);
}

void GLCanvas::render() {
    if (!renderData) return;
    //syncContentTextures();

    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFBO_);
    glEnable(GL_BLEND);
    recRender(renderData);
    glDisable(GL_BLEND);
    glBindFramebuffer(GL_FRAMEBUFFER, defaultFBO_);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void GLCanvas::capture(const std::string& filePath) {
    int width = renderData->width;
    int height = renderData->height;
    std::vector<unsigned char> pixels(width * height * 4);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());

    // 这里可以将像素数据保存为文件，例如使用 stb_image_write 库
    std::ofstream file(filePath, std::ios::binary);
    if (file.is_open()) {
        file.write(reinterpret_cast<const char*>(pixels.data()), pixels.size());
        file.close();
    }
}

int GLCanvas::arraySizeForType(int type) {
    switch (type) {
        case GL_FLOAT_VEC2:
        case GL_INT_VEC2:
        case GL_BOOL_VEC2:
            return 2;

        case GL_FLOAT_VEC3:
        case GL_INT_VEC3:
        case GL_BOOL_VEC3:
            return 3;

        case GL_FLOAT_VEC4:
        case GL_INT_VEC4:
        case GL_BOOL_VEC4:
        case GL_FLOAT_MAT2:
            return 4;

        case GL_FLOAT_MAT3:
            return 9;

        case GL_FLOAT_MAT4:
            return 16;

        default:
            throw std::runtime_error("Invalid array type: " + std::to_string(type));
    }
}

bool GLCanvas::haveRemainingToPreload() {
    // 遍历 imagesToPreload 中的每个 Uri（这里用 std::string 表示）
    for (const auto& uri : imagesToPreload) {
        // 检查 preloaded 集合中是否不包含当前的 uri
        if (std::find(preloaded.begin(), preloaded.end(), uri) == preloaded.end()) {
            // 如果不包含，则说明还有需要预加载的项，返回 true
            return true;
        }
    }
    // 如果遍历完所有的 uri 都在 preloaded 集合中，说明没有剩余需要预加载的项，返回 false
    return false;
}