// demos_scientific.cpp — demos para los 5 charts cientificos del issue 0034:
//   treemap, sankey, chord, contour, voronoi.

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

#include "viz/treemap.h"
#include "viz/sankey.h"
#include "viz/chord.h"
#include "viz/contour.h"
#include "viz/voronoi.h"

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

namespace gallery {

// ---------------------------------------------------------------------------
// treemap
// ---------------------------------------------------------------------------

void demo_treemap() {
    demo_header("treemap", "v1.0.0",
        "Squarified treemap (Bruls et al.) para jerarquias planas con valores. "
        "Algoritmo puro separado del render.");

    section("Gastos por categoria");
    {
        std::vector<TreemapItem> items = {
            {"vivienda",   950.0f, IM_COL32(180, 120, 200, 255)},
            {"comida",     320.0f, IM_COL32(120, 180, 200, 255)},
            {"transporte", 180.0f, IM_COL32(200, 180, 120, 255)},
            {"ocio",       140.0f, IM_COL32(200, 120, 160, 255)},
            {"salud",       90.0f, IM_COL32(120, 200, 160, 255)},
            {"otros",       60.0f, IM_COL32(160, 160, 200, 255)},
        };
        treemap("##gastos", items, ImVec2(-1, 320));
    }

    code_block(
        "std::vector<TreemapItem> items = {\n"
        "    {\"vivienda\",   950.0f, IM_COL32(180,120,200,255)},\n"
        "    {\"comida\",     320.0f, IM_COL32(120,180,200,255)},\n"
        "    ...\n"
        "};\n"
        "treemap(\"##gastos\", items, ImVec2(-1, 320));"
    );
}

// ---------------------------------------------------------------------------
// sankey
// ---------------------------------------------------------------------------

void demo_sankey() {
    demo_header("sankey", "v1.0.0",
        "Sankey diagram para flujos source -> target. BFS topologico para columnas, "
        "bandas curvas (bezier cubico) para los links. Asume DAG.");

    section("Clientes -> productos -> categorias");
    {
        std::vector<SankeyNode> nodes = {
            {"premium"},   {"basicos"},
            {"laptops"},   {"phones"},   {"tablets"},
            {"hardware"},  {"software"},  {"servicios"},
        };
        std::vector<SankeyLink> links = {
            // clientes -> productos
            {0, 2, 80}, {0, 3, 30}, {0, 4, 15},
            {1, 3, 60}, {1, 4, 40}, {1, 2, 20},
            // productos -> categorias
            {2, 5, 70}, {2, 6, 30},
            {3, 5, 50}, {3, 7, 40},
            {4, 6, 35}, {4, 7, 20},
        };
        sankey("##flow", nodes, links, ImVec2(-1, 360));
    }

    code_block(
        "std::vector<SankeyNode> nodes = {{\"premium\"}, {\"basicos\"}, ...};\n"
        "std::vector<SankeyLink> links = {{0, 2, 80}, {0, 3, 30}, ...};\n"
        "sankey(\"##flow\", nodes, links, ImVec2(-1, 360));"
    );
}

// ---------------------------------------------------------------------------
// chord
// ---------------------------------------------------------------------------

void demo_chord() {
    demo_header("chord", "v1.0.0",
        "Chord diagram para matrices NxN. Arcos proporcionales a sum(row) + cuerdas "
        "internas con bezier cubico.");

    section("Flujos entre paises (matriz 6x6 simetrica)");
    {
        constexpr int N = 6;
        // simetrica de "comercio" entre 6 paises
        static float M[N * N] = {
            0,  10,  6,  12,  4,  3,
            10,  0, 14,   3,  8,  2,
            6,  14,  0,   9, 11,  5,
            12,  3,  9,   0,  7,  6,
            4,   8, 11,   7,  0, 13,
            3,   2,  5,   6, 13,  0,
        };
        static const char* labels[N] = {"ESP", "FRA", "ITA", "DEU", "PRT", "GBR"};
        chord("##chord", M, N, labels, ImVec2(420, 420));
    }

    code_block(
        "float M[N*N] = {  // simetrica\n"
        "    0, 10, 6, 12, 4, 3,\n"
        "    10, 0, 14, 3, 8, 2,\n"
        "    ...\n"
        "};\n"
        "const char* labels[6] = {\"ESP\",\"FRA\",\"ITA\",\"DEU\",\"PRT\",\"GBR\"};\n"
        "chord(\"##c\", M, 6, labels);"
    );
}

// ---------------------------------------------------------------------------
// contour
// ---------------------------------------------------------------------------

void demo_contour() {
    demo_header("contour", "v1.0.0",
        "Contour plot 2D via marching squares. Para una gaussiana centrada los "
        "contornos resultantes son aproximadamente concentricos.");

    constexpr int N = 32;
    static float grid[N * N];
    static bool init = false;
    if (!init) {
        // Mezcla de 2 gaussianas (peak central + secundario)
        for (int y = 0; y < N; y++) {
            for (int x = 0; x < N; x++) {
                float dx1 = x - N * 0.45f, dy1 = y - N * 0.5f;
                float dx2 = x - N * 0.75f, dy2 = y - N * 0.3f;
                float v   = std::exp(-(dx1 * dx1 + dy1 * dy1) / 70.0f)
                          + 0.55f * std::exp(-(dx2 * dx2 + dy2 * dy2) / 30.0f);
                grid[y * N + x] = v;
            }
        }
        init = true;
    }
    static const float levels[] = {0.15f, 0.30f, 0.50f, 0.70f, 0.90f};
    contour("##gauss", grid, N, N, levels, 5, ImVec2(-1, 320));

    code_block(
        "constexpr int N = 32;\n"
        "float grid[N*N];\n"
        "for (int y = 0; y < N; y++)\n"
        "    for (int x = 0; x < N; x++) {\n"
        "        float dx = x - N/2.0f, dy = y - N/2.0f;\n"
        "        grid[y*N + x] = std::exp(-(dx*dx + dy*dy) / 80.0f);\n"
        "    }\n"
        "float levels[] = {0.15f, 0.30f, 0.50f, 0.70f, 0.90f};\n"
        "contour(\"##gauss\", grid, N, N, levels, 5);"
    );
}

// ---------------------------------------------------------------------------
// voronoi
// ---------------------------------------------------------------------------

void demo_voronoi() {
    demo_header("voronoi", "v1.0.0",
        "Diagrama de Voronoi via raster brute-force (MVP). Tiles 4x4 px coloreados "
        "por el seed mas cercano. Suficiente para N <= 200.");

    constexpr int N = 30;
    static ImVec2 seeds [N];
    static ImU32  colors[N];
    static bool   init = false;
    if (!init) {
        unsigned seed = 7;
        auto rnd = [&]() {
            seed = seed * 1103515245u + 12345u;
            return (float)((seed >> 16) & 0x7fff) / 32768.0f;
        };
        // El render escala automaticamente; las posiciones se asumen en coords del rect.
        // Como no sabemos W/H aqui, usamos coords aproximadas para 600x300 y el clip
        // dentro de voronoi se encarga de mantenerlas en rango.
        for (int i = 0; i < N; i++) {
            seeds [i] = ImVec2(rnd() * 600.0f, rnd() * 300.0f);
            colors[i] = IM_COL32(40 + (int)(rnd() * 200),
                                 40 + (int)(rnd() * 200),
                                 60 + (int)(rnd() * 195),
                                 230);
        }
        init = true;
    }
    voronoi("##v", seeds, N, colors, ImVec2(-1, 300));

    code_block(
        "ImVec2 seeds[30];\n"
        "ImU32  colors[30];\n"
        "for (int i = 0; i < 30; i++) {\n"
        "    seeds [i] = ImVec2(rnd() * 600.0f, rnd() * 300.0f);\n"
        "    colors[i] = IM_COL32(rnd_byte(), rnd_byte(), rnd_byte(), 230);\n"
        "}\n"
        "voronoi(\"##v\", seeds, 30, colors, ImVec2(-1, 300));"
    );
}

} // namespace gallery
