#pragma once

#include <string>
#include <unordered_map>

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

namespace ge {

enum InputKind {
    INPUT_NONE = 0,
    INPUT_OPERATIONS,
    // Futuro: INPUT_JSON, INPUT_JSONL, INPUT_GRAPHML, ...
};

struct InputArgs {
    InputKind   kind = INPUT_NONE;
    const char* uri  = nullptr; // path al SQLite (operations) o al fichero
};

// Dispatcher de sources. Devuelve true si la carga succeeded; en cualquier
// caso `stats` se rellena (errors > 0 ante fallo).
bool load_graph(const InputArgs& args, GraphData* out, graph::GraphLoadStats* stats);

// Reload helper — usa la misma uri que la ultima `load_graph` exitosa.
// Llama a `graph_free(out)` y vuelve a invocar `load_graph(args, out, stats)`.
// Si `group_expanded` no es null, aplica el filtro de grupos (issue 0035b)
// tras la carga: oculta hijos cuyo group_id apunta a un grupo no expandido,
// reescribe extremos de aristas que quedan dentro de grupos colapsados al
// cuadrado del grupo, y deduplica aristas grupo-a-grupo a una linea por par.
bool reload_graph(const InputArgs& args, GraphData* out, graph::GraphLoadStats* stats,
                  const std::unordered_map<std::string, bool>* group_expanded = nullptr);

// Aplica el filtro de grupos in-place sobre `g` consultando `db_path` para
// recuperar `group_id` por entidad. `group_expanded` mapea entity_id (string)
// del nodo Group → bool (true = expandido). Reglas:
//   - Nodo con group_id != NULL y grupo padre no expandido → oculto (NF_VISIBLE
//     limpiado y removido del array, indices de aristas re-mapeados).
//   - Arista cuyo extremo cae en grupo colapsado → extremo redirigido al
//     nodo del grupo. Si el otro extremo tambien cae en el MISMO grupo
//     colapsado → arista interna, se descarta.
//   - Aristas con AMBOS extremos en grupos colapsados distintos → dedup por
//     par (group_a, group_b) sin orden, una sola linea por par + relacion.
// Idempotente sobre un grafo ya filtrado (no quedan group_id ocultos).
// Retorna true si tuvo exito; en caso de error de DB devuelve false sin
// alterar el grafo.
bool apply_group_filter(GraphData* g, const char* db_path,
                        const std::unordered_map<std::string, bool>& group_expanded);

// Issue 0035e: para cada nodo Group, si todos sus hijos comparten un
// unico `type_ref`, reasigna el `type_id` del Group al type_id de ese
// tipo y fija `shape_override = SHAPE_SQUARE` para preservar la forma
// cuadrada. Si la familia es heterogenea, el nodo conserva su visual
// generico de Group. No-op si la BD no tiene group_id o no hay Groups.
bool apply_group_inherited_visuals(GraphData* g, const char* db_path);

} // namespace ge
