// Demo de sql_workbench (Core, issue 0032).
//
// Abre `registry.db` en modo readonly y deja que el componente liste sus
// tablas en la sidebar. La idea es probar el ciclo Run + tabla + historial
// contra una DB real sin riesgo de mutarla.

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

#include "core/sql_workbench.h"
#include "core/tokens.h"

#include <imgui.h>
#include <sqlite3.h>

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>

namespace gallery {

namespace {

struct SqlDemoState {
    sqlite3*              db    = nullptr;
    fn::SqlWorkbenchState wb;
    bool                  tried_open = false;
    std::string           db_path;
    std::string           open_error;
};

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

// Resuelve la ruta a registry.db: env FN_REGISTRY_ROOT/registry.db si existe,
// si no, prueba ./registry.db, ../registry.db, ../../registry.db (build tree).
std::string resolve_registry_db() {
    if (const char* env = std::getenv("FN_REGISTRY_ROOT")) {
        std::string p = std::string(env) + "/registry.db";
        if (FILE* f = std::fopen(p.c_str(), "rb")) { std::fclose(f); return p; }
    }
    const char* candidates[] = {
        "registry.db",
        "../registry.db",
        "../../registry.db",
        "../../../registry.db",
        "../../../../registry.db",
    };
    for (const char* c : candidates) {
        if (FILE* f = std::fopen(c, "rb")) { std::fclose(f); return c; }
    }
    return "";
}

void ensure_open() {
    auto& s = state();
    if (s.tried_open) return;
    s.tried_open = true;

    s.db_path = resolve_registry_db();
    if (s.db_path.empty()) {
        s.open_error = "registry.db not found (tried FN_REGISTRY_ROOT and parent dirs)";
        return;
    }
    int rc = sqlite3_open_v2(s.db_path.c_str(), &s.db,
                             SQLITE_OPEN_READONLY, nullptr);
    if (rc != SQLITE_OK) {
        s.open_error = sqlite3_errmsg(s.db);
        if (s.db) { sqlite3_close(s.db); s.db = nullptr; }
        return;
    }
    s.wb.readonly = true;
    // Query inicial mas util para el demo: lista de funciones del registry.
    s.wb.query =
        "SELECT id, kind, purity, domain\n"
        "FROM functions\n"
        "ORDER BY id\n"
        "LIMIT 50;";
}

} // namespace

void demo_sql_workbench() {
    using namespace fn_tokens;

    demo_header("sql_workbench", "v1.0.0",
        "Workbench SQL: editor con highlighting, schema sidebar, tabla de "
        "resultados e historial. Ejecuta queries contra una sqlite3* del caller. "
        "En este demo, registry.db abierto en modo readonly.");

    ensure_open();
    auto& s = state();

    if (!s.open_error.empty()) {
        ImGui::PushStyleColor(ImGuiCol_Text, colors::error);
        ImGui::TextWrapped("could not open registry.db: %s", s.open_error.c_str());
        ImGui::PopStyleColor();
        ImGui::PushStyleColor(ImGuiCol_Text, colors::text_muted);
        ImGui::TextWrapped("Set FN_REGISTRY_ROOT to the repo root or run from the repo cwd.");
        ImGui::PopStyleColor();
        return;
    }

    ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim);
    ImGui::Text("db: %s (readonly)", s.db_path.c_str());
    ImGui::PopStyleColor();

    section("workbench");
    {
        ImVec2 avail = ImGui::GetContentRegionAvail();
        // Reserva un pelin para el code_block de abajo.
        float h = avail.y - 110.0f;
        if (h < 320.0f) h = 320.0f;
        fn::sql_workbench("##gallery_sql", s.db, s.wb, ImVec2(-1, h));
    }

    code_block(
        "sqlite3* db = nullptr;\n"
        "sqlite3_open_v2(\"registry.db\", &db, SQLITE_OPEN_READONLY, nullptr);\n"
        "fn::SqlWorkbenchState st;\n"
        "st.readonly = true;\n"
        "fn::sql_workbench(\"##sql\", db, st, ImVec2(-1, -1));"
    );
}

} // namespace gallery
