//! Per-session typed registry holding `Arc<dyn TraitName>` query
//! providers keyed by `TypeId<Arc<dyn TraitName>>`.
//!
//! Mirrors the existing engine-side `CapabilityRegistry` shape
//! (TypeId-keyed lookup) but lives in the SDK so plugins can read
//! it through `GameContext::queries()`.

use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::Arc;

/// Type-erased map of query providers. Each entry is one
/// `Arc<dyn TraitName>` boxed as `Arc<dyn Any + Send + Sync>` and
/// keyed on the `TypeId` of the concrete `Arc<dyn TraitName>` (not
/// the trait's own TypeId — `dyn Trait` is unsized, but
/// `Arc<dyn Trait>` is sized and `'static` when the trait bound
/// is, so its `TypeId` is well-defined).
#[derive(Default)]
pub struct QueryRegistry {
    map: HashMap<TypeId, Arc<dyn Any + Send + Sync>>,
}

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

    /// Install a query provider for trait `Q`. Replaces any existing
    /// provider for the same trait (last-write-wins at this layer;
    /// the engine's manifest-driven resolver picks providers
    /// deterministically before calling `insert`).
    pub fn insert<Q: ?Sized + Send + Sync + 'static>(&mut self, provider: Arc<Q>)
    where
        Arc<Q>: Any + Send + Sync,
    {
        let key = TypeId::of::<Arc<Q>>();
        self.map.insert(key, Arc::new(provider));
    }

    /// Fetch the query provider for trait `Q`, if installed. Returns
    /// `None` when no provider is registered (e.g., a test harness
    /// without the corresponding engine subsystem wired).
    pub fn get<Q: ?Sized + Send + Sync + 'static>(&self) -> Option<Arc<Q>>
    where
        Arc<Q>: Any + Send + Sync + Clone,
    {
        let key = TypeId::of::<Arc<Q>>();
        let entry = self.map.get(&key)?;
        let typed = entry.clone().downcast::<Arc<Q>>().ok()?;
        Some((*typed).clone())
    }

    /// Whether a provider is registered for trait `Q`. Cheap; no
    /// downcast or clone.
    pub fn contains<Q: ?Sized + Send + Sync + 'static>(&self) -> bool
    where
        Arc<Q>: Any,
    {
        self.map.contains_key(&TypeId::of::<Arc<Q>>())
    }

    pub fn len(&self) -> usize {
        self.map.len()
    }

    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }
}
