// Demo de gl_texture_load (cpp/functions/gfx/gl_texture_load.{h,cpp}).
// Carga assets/sample.png y lo muestra con ImGui::Image. Sliders para tint
// RGB que se aplican como modulacion (ImGui::Image acepta tint_col).
//
// Limitacion: el "zoom UV" se simula moviendo uv0/uv1 (que ImGui::Image acepta
// nativamente). Asi evitamos compilar un shader custom adicional para la demo.

#include "demos.h"
#include "demo.h"

#include "gfx/gl_texture_load.h"
#include "gfx/gl_loader.h"

#include <imgui.h>
#include <cstdio>
#include <cstring>

namespace gallery {

namespace {

struct TextureState {
    fn::GlTexture tex{};
    bool          tried_load = false;
    std::string_view err;
    char          err_buf[256] = {0};
    float         tint[3]      = {1.0f, 1.0f, 1.0f};
    float         zoom          = 1.0f; // 1.0 = sin zoom; >1 hace UV mas pequeno
};

TextureState& state() {
    static TextureState s;
    return s;
}

// Resuelve un path para el asset. Probamos varios candidatos relativos al cwd
// del binario (puede lanzarse desde build/ o desde la raiz del repo).
const char* resolve_sample_path() {
    static const char* candidates[] = {
        "assets/sample.png",
        "apps/primitives_gallery/assets/sample.png",
        "cpp/apps/primitives_gallery/assets/sample.png",
        "../cpp/apps/primitives_gallery/assets/sample.png",
        "../../cpp/apps/primitives_gallery/assets/sample.png",
        "../../../cpp/apps/primitives_gallery/assets/sample.png",
        nullptr,
    };
    for (int i = 0; candidates[i]; i++) {
        FILE* f = std::fopen(candidates[i], "rb");
        if (f) { std::fclose(f); return candidates[i]; }
    }
    return candidates[0]; // devolver el primer candidato para que el error sea mas descriptivo
}

} // namespace

void demo_gl_texture() {
    demo_header("gl_texture_load", "v1.0.0",
        "Carga PNG/JPG/HDR desde disco a una textura GL lista para sampler2D. "
        "Vendorea stb_image (cpp/vendor/stb/). Demo: assets/sample.png "
        "(damero 256x256), tint RGB modulando ImGui::Image, zoom UV.");

    auto& s = state();

    if (!s.tried_load) {
        // Asegurar simbolos GL resueltos (Linux no-op, Windows wglGetProcAddress).
        fn::gfx::gl_loader_init();
        const char* path = resolve_sample_path();
        s.tex = fn::gl_texture_load(path, /*flip_y=*/true, /*srgb=*/false);
        if (!s.tex.ok()) {
            std::snprintf(s.err_buf, sizeof(s.err_buf),
                "no se pudo cargar '%s': %s",
                path, fn::gl_texture_last_error());
        }
        s.tried_load = true;
    }

    if (!s.tex.ok()) {
        ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "%s", s.err_buf);
        ImGui::TextWrapped(
            "El binario busca el PNG en varios paths relativos al cwd. "
            "Lanzar desde la raiz del repo o desde cpp/build/ deberia funcionar.");
        return;
    }

    section("Texture info");
    ImGui::Text("size:     %d x %d px", s.tex.w, s.tex.h);
    ImGui::Text("channels: %d (forzado a RGBA en upload)", s.tex.channels);
    ImGui::Text("gl_id:    %u", (unsigned)s.tex.id);

    section("Tint + zoom");
    ImGui::SliderFloat3("tint RGB", s.tint, 0.0f, 2.0f, "%.2f");
    ImGui::SliderFloat("zoom UV",   &s.zoom, 0.25f, 4.0f, "%.2fx");

    section("Preview");

    // Calcular UVs centradas con zoom: 1.0 = (0,0)-(1,1), 2.0 = (0.25,0.25)-(0.75,0.75)
    float u_half = 0.5f / (s.zoom > 0.001f ? s.zoom : 0.001f);
    ImVec2 uv0(0.5f - u_half, 0.5f - u_half);
    ImVec2 uv1(0.5f + u_half, 0.5f + u_half);

    ImVec4 tint(s.tint[0], s.tint[1], s.tint[2], 1.0f);

    // Conversion GLuint -> ImTextureID. ImGui::Image acepta cualquier id de
    // textura del backend; en imgui_impl_opengl3 es directamente el GLuint.
    ImTextureID tid = (ImTextureID)(intptr_t)s.tex.id;

    ImGui::ImageWithBg(tid, ImVec2(384.0f, 384.0f), uv0, uv1,
                       ImVec4(0, 0, 0, 0), tint);

    code_block(
        "#include \"gfx/gl_texture_load.h\"\n\n"
        "auto tex = fn::gl_texture_load(\"assets/sample.png\");\n"
        "if (!tex.ok()) {\n"
        "    fprintf(stderr, \"%s\\n\", fn::gl_texture_last_error());\n"
        "    return 1;\n"
        "}\n"
        "// uso en shader:\n"
        "glUseProgram(prog);\n"
        "fn::gl_texture_bind_uniform(prog, \"u_tex\", tex, /*unit=*/0);\n"
        "glDrawArrays(GL_TRIANGLES, 0, 6);\n\n"
        "// o en ImGui directamente:\n"
        "ImGui::Image((ImTextureID)(intptr_t)tex.id, ImVec2(w, h));"
    );
}

} // namespace gallery
