use crate::*;

/// Inner storage for a dynamic node render closure.
///
/// Boxes a `dyn FnMut(&mut HookContext) -> VirtualNode` so it can be stored behind `Rc<UnsafeCell<>>`.
#[derive(CustomDebug, Data, New)]
pub(crate) struct RenderFnInner {
    /// The boxed render closure.
    #[debug(skip)]
    #[get(pub(crate))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) render_fn: Box<dyn FnMut(&mut HookContext) -> VirtualNode>,
}

/// Represents a text node in the virtual DOM.
///
/// Text nodes may optionally be bound to a reactive signal for automatic updates.
#[derive(Clone, CustomDebug, Data, New)]
pub struct TextNode {
    /// The text content.
    #[get(pub(crate))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) content: String,
    /// An optional signal that drives reactive text updates.
    #[debug(skip)]
    #[get(pub(crate))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) signal: Option<Signal<String>>,
}

/// A closure-based dynamic node that re-renders when its dependency signals change.
///
/// Holds a shared reference to a heap-allocated render closure that produces a fresh
/// `VirtualNode` on each evaluation. The renderer subscribes to the closure's
/// signals and patches the DOM automatically.
/// Contains a `HookContext` that persists hook state (like `use_signal`) across
/// re-renders, ensuring that signal values are not reset when the render function
/// is called again.
///
/// Uses `Rc<UnsafeCell<>>` instead of `Rc<RefCell<>>` to avoid runtime borrow
/// checking overhead. Safety is guaranteed by the single-threaded WASM context.
/// The `Rc` provides automatic memory management — the render closure is freed
/// when the last reference (either in the VirtualNode tree or the signal update
/// callback) is dropped.
#[derive(Clone, CustomDebug, Data, New)]
pub struct DynamicNode {
    /// Shared reference to the heap-allocated render closure inner state.
    /// `Rc` ensures automatic deallocation; `UnsafeCell` allows mutable access
    /// without RefCell overhead.
    #[debug(skip)]
    #[get(pub(crate))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) render_fn: Rc<UnsafeCell<RenderFnInner>>,
    /// Persistent hook context for this dynamic node, storing signal
    /// state and other hook values across render cycles.
    #[get(pub(crate))]
    #[get_mut(pub(crate))]
    #[set(pub(crate))]
    pub(crate) hook_context: HookContext,
}
