#pragma once
#include "imgui.h"
#include <vector>

struct GraphData;
struct GraphRenderer;
struct SpatialHash;

// Callbacks opcionales del viewport. Se invocan dentro del frame ImGui — el
// caller puede abrir popups (`ImGui::OpenPopup`) o cambiar estado de la app.
// Cualquier puntero NULL se ignora.
struct GraphViewportCallbacks {
    void (*on_context_menu)(int node_idx, ImVec2 screen_pos, void* user) = nullptr;
    void (*on_double_click)(int node_idx, void* user) = nullptr;
    void* user = nullptr;
};

// Persistent state for graph_viewport widget. Create one per viewport and keep
// alive across frames.
struct GraphViewportState {
    // Camera
    float cam_x = 0.0f, cam_y = 0.0f;
    float zoom     = 1.0f;
    float zoom_min = 0.01f, zoom_max = 50.0f;

    // Interaction result (read after calling graph_viewport each frame)
    int  hovered_node  = -1;   // node index under cursor, -1 if none
    int  selected_node = -1;   // legacy: ultimo nodo clicado, -1 si ninguno
    bool is_dragging   = false;

    // Multi-seleccion (issue 0049i). `selection` mantiene los indices de
    // todos los nodos seleccionados (orden de insercion). El flag NF_SELECTED
    // se mantiene sincronizado con esta lista.
    std::vector<int> selection;

    // Lasso (issue 0049i). Activado durante Shift+Drag sobre area vacia.
    // Coordenadas en world space.
    bool   lasso_active = false;
    ImVec2 lasso_start  = ImVec2(0.0f, 0.0f);
    ImVec2 lasso_end    = ImVec2(0.0f, 0.0f);

    // Layout
    bool  layout_running = true;  // animate force layout each frame
    float layout_energy  = 0.0f; // kinetic energy from last step

    // Internal — managed by graph_viewport / graph_viewport_destroy
    GraphRenderer* renderer  = nullptr;
    SpatialHash*   spatial   = nullptr;
    bool           initialized = false;

    // Widget pixel dimensions tracked for resize detection
    int render_w = 0, render_h = 0;

    // Node being dragged (-1 = none). Si hay multi-seleccion, todos los
    // seleccionados se mueven solidariamente con el delta del raton.
    int drag_node = -1;
    // Posicion world del raton al iniciar el drag (issue 0049i).
    float drag_anchor_x = 0.0f;
    float drag_anchor_y = 0.0f;
};

// Main viewport widget. Call every ImGui frame.
// id:    unique ImGui widget identifier
// graph: mutable graph data (node positions updated on drag)
// state: persistent state (camera, selection, GPU renderer); must outlive frames
// size:  widget size in pixels — ImVec2(0,0) uses all available space
// cb:    callbacks opcionales (right-click, double-click). Default = sin callbacks.
// Returns true if any user interaction occurred (hover, click, drag, zoom).
bool graph_viewport(const char* id, GraphData& graph, GraphViewportState& state,
                    ImVec2 size = ImVec2(0.0f, 0.0f),
                    const GraphViewportCallbacks& cb = GraphViewportCallbacks{});

// Release GPU resources. Call once when done with the viewport.
void graph_viewport_destroy(GraphViewportState& state);

// Fit camera to current graph bounds with 10% padding.
void graph_viewport_fit(GraphData& graph, GraphViewportState& state);

// Helpers de multi-seleccion (puros respecto al state). Mantienen
// NF_SELECTED sincronizado.
void graph_viewport_clear_selection(GraphData& graph, GraphViewportState& state);
void graph_viewport_add_to_selection(GraphData& graph, GraphViewportState& state, int node_idx);
void graph_viewport_toggle_selection(GraphData& graph, GraphViewportState& state, int node_idx);
bool graph_viewport_is_selected(const GraphViewportState& state, int node_idx);
