//! Wire-shaped reachable-set for UC-04 distance metrics.
//!
//! `ReachableSet` lives in the SDK so it can both:
//!   - be stored in the engine's `ReachabilityCache` (server-side), and
//!   - cross the wire on `ServerFrame::Snapshot.reachability` to
//!     populate the client-side `EvalContext::distance` lookup.
//!
//! The cache itself + BFS implementations live in
//! `core/engine/src/reachability.rs` — the engine layer is the only one
//! that ever computes a `ReachableSet`. Clients only deserialize.

use std::collections::HashMap;

use crate::board::BoardNodeId;

/// Per-entity reachable-set: every node reachable from the entity's
/// position, mapped to its distance (in cells / hops, kind-dependent).
///
/// Crosses the wire on `ServerFrame::Snapshot.reachability`.
#[derive(Default, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct ReachableSet {
    /// Reachable nodes mapped to their distance from the source.
    pub cells: HashMap<BoardNodeId, i64>,
}

impl ReachableSet {
    pub fn new() -> Self {
        Self::default()
    }

    /// Distance from the source to `node`, if reachable.
    pub fn distance_to(&self, node: BoardNodeId) -> Option<i64> {
        self.cells.get(&node).copied()
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "wire")]
    use super::*;

    #[cfg(feature = "wire")]
    #[test]
    fn reachable_set_postcard_round_trips() {
        let s = ReachableSet {
            cells: HashMap::from([(BoardNodeId(0), 0), (BoardNodeId(5), 3), (BoardNodeId(99), 12)]),
        };
        let bytes = postcard::to_allocvec(&s).unwrap();
        let back: ReachableSet = postcard::from_bytes(&bytes).unwrap();
        assert_eq!(s, back);
    }
}
