#pragma once
#include <string>
#include <vector>

/// fn_ring — geometria pura para layout en anillos concentricos + sectores radiales.
/// Pure: sin I/O, sin estado global, sin RNG. Misma entrada → mismo output siempre.
/// C++17 STL only.

namespace fn_ring {

struct LayoutInput {
    std::string id;        // identidad unica para mapeo deterministico
    std::string status;    // categoria libre — mapeada al ring via status_map
    std::string domain;    // categoria libre — mapeada al sector via domain_order
    float       recency = 0.0f; // 0..1, ordena DENTRO de un (ring,sector) bin (desc)
};

struct LayoutOutput {
    std::string id;
    float       x            = 0.0f;
    float       y            = 0.0f;
    int         ring         = -1;  // -1 = nodo descartado (status no mapeado)
    int         sector       = 0;
    int         rank_in_bin  = 0;   // 0..N-1 dentro del bin (ring,sector)
};

struct LayoutConfig {
    int   n_sectors   = 18;
    float center_x    = 0.0f;
    float center_y    = 0.0f;
    // ring_radii[i]   = radio interno del ring i
    // ring_radii[i+1] = radio externo del ring i
    // Default: 5 rings (0..4)
    std::vector<float> ring_radii { 0.0f, 150.0f, 280.0f, 450.0f, 650.0f, 850.0f };
    float bin_padding  = 14.0f; // padding interior del bin en pixels
    float start_angle  = 0.0f;  // rotacion global del sector 0 en radianes
};

/// Mapea strings de status a indice de ring.
/// Status no listado → ring -1 (nodo descartado).
///
/// Default canonico (usado cuando se pasa vector vacio):
///   {"completado",0}, {"completed",0},
///   {"in-progress",1},
///   {"pendiente_unlocked",2}, {"unlocked",2}, {"pending",2},
///   {"pendiente",3}, {"locked",3},
///   {"deferred",4}, {"bloqueado",4}
using StatusRingMap = std::vector<std::pair<std::string, int>>;

/// Mapea strings de domain a indice de sector [0..n_sectors-1].
/// Domains no listados → sector n_sectors-1 (sector "otros").
using DomainOrder = std::vector<std::string>;

/// Compute ring+sector layout deterministico.
///
/// Para cada nodo:
///   1. ring = status_map[node.status]; descartar si -1.
///   2. sector = index(domain_order, node.domain); fallback n_sectors-1.
///   3. Bin (ring, sector): ordenar por (recency desc, id asc), distribuir
///      uniformemente en la banda radial con padding. Sub-jitter angular
///      deterministico via hash del id cuando el bin esta sobrecargado.
///   4. theta = start_angle + (sector + 0.5) * (2*PI / n_sectors) + jitter
///   5. x = center.x + r * cos(theta); y = center.y + r * sin(theta)
///
/// Ring 0 con radio interno 0: usa r_inner = 30.0f para no colocar nodos
/// en el origen exacto (reservado para HUD overlay).
std::vector<LayoutOutput>
compute_ring_layout(const std::vector<LayoutInput>& nodes,
                    const LayoutConfig& cfg,
                    const StatusRingMap& status_map = {},
                    const DomainOrder& domain_order = {});

} // namespace fn_ring
