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

#include "viz/bar_chart.h"
#include "viz/pie_chart.h"
#include "viz/line_plot.h"
#include "viz/scatter_plot.h"
#include "viz/histogram.h"
#include "viz/sparkline.h"
#include "core/tokens.h"

#include <imgui.h>
#include <cmath>
#include <vector>

namespace gallery {

// ---------------------------------------------------------------------------
// bar_chart
// ---------------------------------------------------------------------------

void demo_bar_chart() {
    demo_header("bar_chart", "v1.2.0",
        "Barras verticales con ejes pineados, tooltip al hover y auto-rotacion 45 grados "
        "de labels cuando no caben horizontalmente.");

    section("Labels que caben horizontalmente");
    {
        const char* langs[]   = {"go", "py", "ts", "sh", "cpp"};
        float values[]        = {412.0f, 187.0f, 94.0f, 63.0f, 36.0f};
        bar_chart("##bar_short", langs, values, 5, 0.67f, 200.0f);
    }

    section("Labels largos que obligan a rotar");
    {
        const char* domains[] = {
            "core", "infrastructure", "finance", "datascience",
            "cybersecurity", "notebook", "browser"
        };
        float values[] = {412, 187, 94, 63, 42, 38, 22};
        bar_chart("##bar_long", domains, values, 7, 0.67f, 240.0f);
    }

    code_block(
        "const char* labels[] = {\"go\",\"py\",\"ts\",\"sh\",\"cpp\"};\n"
        "float values[] = {412,187,94,63,36};\n"
        "bar_chart(\"##lang\", labels, values, 5);            // h=200 default\n"
        "bar_chart(\"##lang\", labels, values, 5, 0.8f, 300); // bar_w + altura"
    );
}

// ---------------------------------------------------------------------------
// pie_chart
// ---------------------------------------------------------------------------

void demo_pie_chart() {
    demo_header("pie_chart", "v1.1.0",
        "Pie/donut con aspect 1:1, ejes pineados y tooltip por slice con "
        "valor absoluto + porcentaje.");

    if (ImGui::BeginTable("##pie_grid", 2, ImGuiTableFlags_SizingStretchSame)) {
        ImGui::TableNextRow();

        ImGui::TableSetColumnIndex(0);
        {
            const char* labels[] = {"Pure", "Impure"};
            float values[] = {412.0f, 278.0f};
            variant_label("Pie (radius auto)");
            pie_chart("##pie_auto", labels, values, 2, 0.0f, 260.0f);
        }

        ImGui::TableSetColumnIndex(1);
        {
            const char* labels[] = {"function", "pipeline", "component"};
            float values[] = {618.0f, 42.0f, 230.0f};
            variant_label("Donut (radius = -0.45)");
            pie_chart("##pie_donut", labels, values, 3, -0.45f, 260.0f);
        }

        ImGui::EndTable();
    }

    code_block(
        "const char* labels[] = {\"Pure\",\"Impure\"};\n"
        "float values[] = {412, 278};\n"
        "pie_chart(\"##p\", labels, values, 2);                 // pie auto\n"
        "pie_chart(\"##p\", labels, values, 2, -0.45f, 260);    // donut"
    );
}

// ---------------------------------------------------------------------------
// line_plot
// ---------------------------------------------------------------------------

void demo_line_plot() {
    demo_header("line_plot", "v1.1.0",
        "Line plot 2D con limites de ejes calculados de min/max y pineados. "
        "Sin auto-fit animado, sin pan/zoom.");

    constexpr int N = 100;
    static float xs[N], ys[N];
    static bool init = false;
    if (!init) {
        for (int i = 0; i < N; i++) {
            xs[i] = static_cast<float>(i) * 0.1f;
            ys[i] = std::sin(xs[i]) + 0.3f * std::sin(xs[i] * 3.5f);
        }
        init = true;
    }
    line_plot("##line", xs, ys, N, 240.0f);

    code_block(
        "line_plot(\"##series\", xs, ys, count);          // h=200 default\n"
        "line_plot(\"##series\", xs, ys, count, 300.0f);  // custom height"
    );
}

// ---------------------------------------------------------------------------
// scatter_plot
// ---------------------------------------------------------------------------

void demo_scatter_plot() {
    demo_header("scatter_plot", "v1.1.0",
        "Puntos dispersos con ejes pineados (5% headroom). Sin interaccion.");

    constexpr int N = 120;
    static float xs[N], ys[N];
    static bool init = false;
    if (!init) {
        unsigned seed = 1234;
        auto rnd = [&]() {
            seed = seed * 1103515245u + 12345u;
            return static_cast<float>((seed >> 16) & 0x7fff) / 32768.0f;
        };
        for (int i = 0; i < N; i++) {
            xs[i] = rnd() * 10.0f;
            ys[i] = 0.5f * xs[i] + rnd() * 3.0f;
        }
        init = true;
    }
    scatter_plot("##sc", xs, ys, N, 240.0f);

    code_block(
        "scatter_plot(\"##xy\", xs, ys, count, 240.0f);"
    );
}

// ---------------------------------------------------------------------------
// histogram
// ---------------------------------------------------------------------------

void demo_histogram() {
    demo_header("histogram", "v1.1.0",
        "Histograma con bins automaticos (Sturges) o manuales. Usa AutoFit "
        "para los bins + Lock para bloquear pan/zoom.");

    constexpr int N = 300;
    static float vals[N];
    static bool init = false;
    if (!init) {
        unsigned seed = 42;
        auto rnd = [&]() {
            seed = seed * 1103515245u + 12345u;
            return static_cast<float>((seed >> 16) & 0x7fff) / 32768.0f;
        };
        // Aproximacion de distribucion normal via box-muller simplificado
        for (int i = 0; i < N; i++) {
            float u1 = rnd() + 1e-6f;
            float u2 = rnd();
            vals[i] = std::sqrt(-2.0f * std::log(u1))
                    * std::cos(2.0f * 3.14159f * u2);
        }
        init = true;
    }
    histogram("##hist", vals, N, -1, 240.0f);

    code_block(
        "histogram(\"##h\", values, count);              // bins=Sturges\n"
        "histogram(\"##h\", values, count, 30, 300.0f);  // 30 bins, h=300"
    );
}

// ---------------------------------------------------------------------------
// sparkline
// ---------------------------------------------------------------------------

void demo_sparkline() {
    demo_header("sparkline", "v1.0.0",
        "Mini grafico de lineas inline (rellenado con alpha + linea). "
        "Pensado para tablas, KPI cards, headers.");

    float up[]   = {10, 12, 11, 15, 18, 17, 20};
    float down[] = {30, 28, 29, 25, 22, 24, 20};
    float flat[] = {10, 10, 10, 10, 10, 10, 10};

    ImGui::Text("Trending up  "); ImGui::SameLine();
    sparkline("##up",   up,   7, ImVec4(0.35f, 0.85f, 0.45f, 1.0f), 140.0f, 22.0f);

    ImGui::Text("Trending down"); ImGui::SameLine();
    sparkline("##down", down, 7, ImVec4(0.90f, 0.30f, 0.30f, 1.0f), 140.0f, 22.0f);

    ImGui::Text("Flat         "); ImGui::SameLine();
    sparkline("##flat", flat, 7, ImVec4(0.55f, 0.55f, 0.55f, 1.0f), 140.0f, 22.0f);

    code_block(
        "float history[] = {10,12,11,15,18,17,20};\n"
        "sparkline(\"##rev\", history, 7, /*color=*/{0.35,0.85,0.45,1}, 140, 22);"
    );
}

} // namespace gallery
