// Smoke tests for graph_viewport (issue 0049i).
// El widget completo necesita un contexto OpenGL + ImGui — eso vive en el
// demo y en el test visual. Aqui solo cubrimos los helpers de seleccion
// (logica pura sobre GraphData / GraphViewportState) que no dependen de GL
// ni de ImGui frame state.

#define CATCH_CONFIG_MAIN
#include "catch_amalgamated.hpp"

#include "viz/graph_viewport.h"
#include "viz/graph_types.h"

#include <vector>

namespace {
struct TG {
    std::vector<GraphNode> nodes;
    GraphData data{};
    void make(int N) {
        nodes.clear();
        for (int i = 0; i < N; ++i) nodes.push_back(graph_node());
        data.nodes = nodes.data();
        data.node_count = (int)nodes.size();
        data.node_capacity = (int)nodes.capacity();
        data.edges = nullptr; data.edge_count = 0; data.edge_capacity = 0;
        data.types = nullptr; data.type_count = 0;
        data.rel_types = nullptr; data.rel_type_count = 0;
    }
};
} // namespace

TEST_CASE("selection: add sets NF_SELECTED and selected_node", "[viewport][selection]") {
    TG g; g.make(5);
    GraphViewportState st;

    graph_viewport_add_to_selection(g.data, st, 2);
    REQUIRE(st.selection.size() == 1);
    REQUIRE(st.selection[0] == 2);
    REQUIRE(st.selected_node == 2);
    REQUIRE((g.nodes[2].flags & NF_SELECTED) != 0);

    // Anadir el mismo no duplica
    graph_viewport_add_to_selection(g.data, st, 2);
    REQUIRE(st.selection.size() == 1);

    graph_viewport_add_to_selection(g.data, st, 4);
    REQUIRE(st.selection.size() == 2);
    REQUIRE(st.selected_node == 4);
}

TEST_CASE("selection: clear unsets all NF_SELECTED", "[viewport][selection]") {
    TG g; g.make(3);
    GraphViewportState st;
    graph_viewport_add_to_selection(g.data, st, 0);
    graph_viewport_add_to_selection(g.data, st, 1);
    graph_viewport_add_to_selection(g.data, st, 2);

    graph_viewport_clear_selection(g.data, st);

    REQUIRE(st.selection.empty());
    REQUIRE(st.selected_node == -1);
    for (int i = 0; i < 3; ++i) {
        REQUIRE((g.nodes[i].flags & NF_SELECTED) == 0);
    }
}

TEST_CASE("selection: toggle adds then removes", "[viewport][selection]") {
    TG g; g.make(3);
    GraphViewportState st;

    graph_viewport_toggle_selection(g.data, st, 1);
    REQUIRE(graph_viewport_is_selected(st, 1));
    REQUIRE((g.nodes[1].flags & NF_SELECTED) != 0);

    graph_viewport_toggle_selection(g.data, st, 1);
    REQUIRE_FALSE(graph_viewport_is_selected(st, 1));
    REQUIRE((g.nodes[1].flags & NF_SELECTED) == 0);
    REQUIRE(st.selected_node == -1);
}

TEST_CASE("selection: out-of-range indices are ignored", "[viewport][selection]") {
    TG g; g.make(2);
    GraphViewportState st;

    graph_viewport_add_to_selection(g.data, st, -1);
    graph_viewport_add_to_selection(g.data, st, 5);
    graph_viewport_toggle_selection(g.data, st, -3);

    REQUIRE(st.selection.empty());
    REQUIRE(st.selected_node == -1);
}

TEST_CASE("selection: is_selected reports membership", "[viewport][selection]") {
    TG g; g.make(4);
    GraphViewportState st;

    graph_viewport_add_to_selection(g.data, st, 0);
    graph_viewport_add_to_selection(g.data, st, 3);

    REQUIRE(graph_viewport_is_selected(st, 0));
    REQUIRE_FALSE(graph_viewport_is_selected(st, 1));
    REQUIRE_FALSE(graph_viewport_is_selected(st, 2));
    REQUIRE(graph_viewport_is_selected(st, 3));
}
