//! `BoardGraphView` — the read-only trait surface of `BoardGraph`.
//!
//! Plugins, capability code, and SDK behavioural code (movement patterns,
//! distance metrics, predicate evaluation) consume the graph through this
//! trait so they don't have to import the concrete `BoardGraph` type from
//! `maat-sdk` (which would couple them to the runtime). The engine's
//! `BoardGraph` implements this trait; mocks and tests can implement it
//! against synthetic data.
//!
//! This is the unblocking piece of PTM-1 phase A: once `MovementPatternProvider`,
//! distance metrics, and predicate evaluation accept `&dyn BoardGraphView`
//! instead of `&BoardGraph`, the trait-data cluster (`MovableData`,
//! `RangedData`, `GatedData`, etc.) can move to `sdk-types` without
//! dragging the behavioural graph code with it.

use crate::board::ids::{EdgeId, FaceId, BoardNodeId};

/// Read-only graph queries used by everything outside the runtime.
///
/// Methods that **mutate** the graph (`add_node`, `add_face`, etc.) live
/// on the concrete `BoardGraph` and are not part of this trait.
pub trait BoardGraphView {
    /// Number of nodes in the graph.
    fn node_count(&self) -> usize;
    /// Number of edges.
    fn edge_count(&self) -> usize;
    /// Number of faces.
    fn face_count(&self) -> usize;

    /// True iff the graph contains a node with this id.
    fn contains_node(&self, id: BoardNodeId) -> bool;
    /// True iff the graph contains an edge with this id.
    fn contains_edge(&self, id: EdgeId) -> bool;
    /// True iff the graph contains a face with this id.
    fn contains_face(&self, id: FaceId) -> bool;

    /// All nodes adjacent to `node` via at least one edge (regardless of
    /// edge direction; for directed edges returns nodes reachable in
    /// either direction).
    fn neighbors(&self, node: BoardNodeId) -> Vec<BoardNodeId>;

    /// All edge ids incident to `node`.
    fn edges_at(&self, node: BoardNodeId) -> Vec<EdgeId>;

    /// The endpoints of `edge`, or `None` if the edge does not exist.
    /// For bidirectional edges, the order is unspecified but stable.
    /// For directed edges, returns `(from, to)`.
    fn endpoints(&self, edge: EdgeId) -> Option<(BoardNodeId, BoardNodeId)>;

    /// Bounding nodes of `face` in walk order, or `None` if the face does
    /// not exist.
    fn face_bounding(&self, id: FaceId) -> Option<Vec<BoardNodeId>>;

    /// All faces incident to `node`.
    fn faces_at_node(&self, node: BoardNodeId) -> Vec<FaceId>;

    /// All faces incident to `edge`.
    fn faces_at_edge(&self, edge: EdgeId) -> Vec<FaceId>;

    /// All faces sharing at least one bounding edge with `face`.
    fn adjacent_faces(&self, face: FaceId) -> Vec<FaceId>;

    /// A monotonically-increasing version counter that increments on
    /// every mutation. Used by views/caches for cheap change detection.
    fn version(&self) -> u64;
}
