//! Reflection / type registry — generic, name-keyed access to components.
//!
//! The engine's *dual-editable types* principle says every component must be
//! readable and writable from the editor, from scripts, and from external tools
//! through **one** representation — without each of those callers knowing the
//! concrete Rust type. The [`TypeRegistry`] is that bridge.
//!
//! A type is registered **once** under a stable name:
//!
//! ```
//! use oxide_engine::reflect::TypeRegistry;
//! use oxide_engine::prelude::*;
//!
//! let mut registry = TypeRegistry::new();
//! registry.register::<Transform>("Transform");
//! registry.register::<Node>("Node");
//! ```
//!
//! From then on, any caller holding only the *name* can round-trip the component
//! on an entity as RON text — which is all a generic inspector or a script needs:
//!
//! ```
//! # use oxide_engine::reflect::TypeRegistry;
//! # use oxide_engine::prelude::*;
//! # let mut registry = TypeRegistry::new();
//! # registry.register::<Transform>("Transform");
//! let mut scene = Scene::new();
//! let e = scene.spawn("thing", Transform::IDENTITY);
//!
//! // Read it generically...
//! let ron = registry.get_ron(scene.world(), e, "Transform").unwrap();
//! // ...and write it back generically, no concrete type at the call site.
//! registry.set_ron(scene.world_mut(), e, "Transform", &ron).unwrap();
//! ```
//!
//! That path is **whole-value** reflection (the unit is one component,
//! serialized). On top of it, [`register_reflected`](TypeRegistry::register_reflected)
//! adds **per-field** reflection — named fields each addressable on their own —
//! for types that derive [`Reflect`], which is what a Unity/Godot-style
//! inspector needs to render one widget per field. Both coexist: the registry
//! addresses *types* by name, while [`Reflect`] addresses *fields* within a
//! value.

use std::collections::BTreeMap;

use hecs::{Component, Entity, World};
use serde::de::DeserializeOwned;
use serde::Serialize;

/// `#[derive(Reflect)]` — generates the [`Reflect`] impl for a struct's public
/// fields. Shares its name with the [`Reflect`] trait (macro vs. type
/// namespace), exactly like `serde`'s `Serialize`.
pub use oxide_engine_derive::Reflect;

/// `#[derive(ReflectEnum)]` — generates the [`ReflectEnum`] impl for a fieldless
/// enum, exposing its variant names for inspector dropdowns.
pub use oxide_engine_derive::ReflectEnum;

/// Errors from generic, name-keyed component access.
#[derive(Debug, thiserror::Error)]
pub enum ReflectError {
    /// No type was registered under this name.
    #[error("no registered type named '{0}'")]
    UnknownType(String),

    /// The entity is not live in the world.
    #[error("entity is not live in this world")]
    NoSuchEntity,

    /// The entity is live but does not carry this component.
    #[error("entity has no component '{0}'")]
    Missing(String),

    /// The RON text could not be parsed into the named type.
    #[error("failed to parse '{type_name}': {message}")]
    Parse {
        /// The registered name being parsed.
        type_name: String,
        /// The underlying parser message.
        message: String,
    },

    /// A per-field operation named a field this type does not reflect.
    #[error("no reflected field named '{0}'")]
    UnknownField(String),

    /// A per-field operation targeted a type registered for whole-value access
    /// only (registered with `register`, not `register_reflected`).
    #[error("type '{0}' is not field-reflected")]
    NotReflected(String),

    /// The RON text could not be parsed into a single field's type.
    #[error("failed to parse field '{field}': {message}")]
    FieldParse {
        /// The field being parsed.
        field: String,
        /// The underlying parser message.
        message: String,
    },
}

/// Per-field reflection generated by `#[derive(Reflect)]`.
///
/// Whole-value reflection ([`TypeRegistry::get_ron`] / [`set_ron`]) is enough
/// for serialization and scripts, but a Unity/Godot-style inspector needs to
/// see *named fields* so it can render one widget per field. `Reflect`
/// provides exactly that, without exposing the concrete field types to the
/// caller: each field is addressed by name and round-trips as RON (the same
/// representation the whole-value path uses).
///
/// Implement it with the derive — see
/// [`oxide_engine_derive::Reflect`](Reflect) (re-exported here as the
/// derive macro of the same name). Only **public** fields are reflected;
/// annotate a public field with `#[reflect(skip)]` to exclude it.
///
/// [`set_ron`]: TypeRegistry::set_ron
pub trait Reflect {
    /// Static descriptors for every reflected field, in declaration order.
    fn fields(&self) -> &'static [FieldInfo];

    /// Serialize one field's current value to RON, or `None` if no field of
    /// that name is reflected.
    fn get_field(&self, name: &str) -> Option<String>;

    /// Parse `value` (RON) into the named field, replacing it.
    ///
    /// # Errors
    /// [`UnknownField`](ReflectError::UnknownField) if the name isn't a
    /// reflected field, or [`FieldParse`](ReflectError::FieldParse) if the
    /// text isn't valid for the field's type.
    fn set_field(&mut self, name: &str, value: &str) -> Result<(), ReflectError>;
}

/// A fieldless enum whose variants can be listed by name.
///
/// Per-field reflection tells the inspector a field's *type name* but not, for
/// an enum-typed field, the set of values it may take. `ReflectEnum` supplies
/// that list so the inspector can render a dropdown instead of a free-text RON
/// box. Register the enum with
/// [`register_enum`](TypeRegistry::register_enum) and the inspector looks its
/// variants up by type name. Derive it with `#[derive(ReflectEnum)]` (unit
/// variants only).
pub trait ReflectEnum {
    /// The enum's variant names, in declaration order. Each is valid RON for
    /// the corresponding unit variant, so it round-trips through
    /// [`get_field`](TypeRegistry::get_field) / [`set_field`](TypeRegistry::set_field).
    fn variants() -> &'static [&'static str];
}

/// A static description of one reflected field.
///
/// `type_name` is the field type's *syntactic* spelling (e.g. `"f32"`,
/// `"bool"`, `"Vec3"`, `"Handle < Font >"`) as written in the source. A
/// generic inspector dispatches a widget on it and falls back to a raw RON
/// editor for types it doesn't recognize.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct FieldInfo {
    /// The field's identifier.
    pub name: &'static str,
    /// The field type's syntactic name.
    pub type_name: &'static str,
    /// `(min, max)` bounds set with `#[reflect(min = X, max = Y)]`. The
    /// inspector uses this to render a `Slider` for a `f32` field whose value
    /// is normalized (e.g. metallic / roughness in `0..=1`); for plain numeric
    /// fields it stays `None` and a `DragValue` is used instead.
    pub range: Option<(f32, f32)>,
}

/// Implementation detail of `#[derive(Reflect)]` — serialize a field to RON.
///
/// Generated code calls this so it never needs `ron` in scope itself.
#[doc(hidden)]
pub fn __reflect_to_ron<T: Serialize>(value: &T) -> Option<String> {
    ron::to_string(value).ok()
}

/// Implementation detail of `#[derive(Reflect)]` — parse a field from RON.
#[doc(hidden)]
pub fn __reflect_from_ron<T: DeserializeOwned>(
    field: &str,
    value: &str,
) -> Result<T, ReflectError> {
    ron::from_str(value).map_err(|err| ReflectError::FieldParse {
        field: field.to_string(),
        message: err.to_string(),
    })
}

/// The monomorphized operations for one registered type, stored as plain
/// function pointers (the closures capture nothing, so they coerce to `fn`).
struct ReflectedType {
    get_ron: fn(&World, Entity) -> Option<String>,
    set_ron: fn(&mut World, Entity, &str) -> Result<(), String>,
    has: fn(&World, Entity) -> bool,
    remove: fn(&mut World, Entity) -> bool,
    /// Per-field operations, present only for types registered with
    /// [`register_reflected`](TypeRegistry::register_reflected) (i.e. `T:
    /// Reflect`). `None` for whole-value-only types. The registry callers
    /// guarantee the component is present before invoking `get`/`set`.
    fields: Option<FieldOps>,
    /// Inserts a `T::default()` on an entity, present only for types registered
    /// with [`register_addable`](TypeRegistry::register_addable) (i.e. `T:
    /// Default`). `None` means the type can't be added from a generic "Add
    /// Component" menu (no zero-arg construction).
    add_default: Option<fn(&mut World, Entity)>,
}

/// The `T: Reflect` field operations, type-erased to function pointers.
struct FieldOps {
    infos: fn(&World, Entity) -> Option<&'static [FieldInfo]>,
    get: fn(&World, Entity, &str) -> Option<String>,
    set: fn(&mut World, Entity, &str, &str) -> Result<(), ReflectError>,
}

/// A registry mapping stable type names to type-erased component operations.
///
/// Owned by the app/module system (Stage 5): each module registers the component
/// types it introduces, so the editor and scripts can address any of them by
/// name. Names are the identity used in serialized data and UI, so they should
/// be stable across versions.
#[derive(Default)]
pub struct TypeRegistry {
    types: BTreeMap<&'static str, ReflectedType>,
    /// Variant lists for registered enum types, keyed by the same syntactic
    /// type name a [`FieldInfo::type_name`] carries, so the inspector can turn
    /// an enum-typed field into a dropdown.
    enums: BTreeMap<&'static str, &'static [&'static str]>,
}

impl TypeRegistry {
    /// An empty registry.
    pub fn new() -> Self {
        Self::default()
    }

    /// Registers component type `T` under `name`.
    ///
    /// `T` must be an ECS component (`Send + Sync + 'static`) and round-trip
    /// through `serde`. Re-registering the same name replaces the entry.
    pub fn register<T>(&mut self, name: &'static str)
    where
        T: Component + Serialize + DeserializeOwned,
    {
        self.types.insert(
            name,
            ReflectedType {
                get_ron: |world, e| {
                    world
                        .get::<&T>(e)
                        .ok()
                        .and_then(|c| ron::to_string(&*c).ok())
                },
                set_ron: |world, e, text| {
                    let value: T = ron::from_str(text).map_err(|err| err.to_string())?;
                    // `contains` is checked by the caller, so insert cannot fail
                    // for a missing entity; map defensively all the same.
                    world
                        .insert_one(e, value)
                        .map_err(|_| "entity is not live".to_string())
                },
                has: |world, e| world.get::<&T>(e).is_ok(),
                remove: |world, e| world.remove_one::<T>(e).is_ok(),
                fields: None,
                add_default: None,
            },
        );
    }

    /// Registers component type `T` with **per-field** reflection in addition
    /// to whole-value access.
    ///
    /// Identical to [`register`](Self::register) but also wires the
    /// [`Reflect`] field operations, so [`field_infos`](Self::field_infos) /
    /// [`get_field`](Self::get_field) / [`set_field`](Self::set_field) work for
    /// this type. This is what lets the editor render a widget per field. Use
    /// it for any type whose fields should be individually editable; use
    /// `register` for opaque types edited only as a whole.
    pub fn register_reflected<T>(&mut self, name: &'static str)
    where
        T: Component + Serialize + DeserializeOwned + Reflect,
    {
        self.types.insert(
            name,
            ReflectedType {
                get_ron: |world, e| {
                    world
                        .get::<&T>(e)
                        .ok()
                        .and_then(|c| ron::to_string(&*c).ok())
                },
                set_ron: |world, e, text| {
                    let value: T = ron::from_str(text).map_err(|err| err.to_string())?;
                    world
                        .insert_one(e, value)
                        .map_err(|_| "entity is not live".to_string())
                },
                has: |world, e| world.get::<&T>(e).is_ok(),
                remove: |world, e| world.remove_one::<T>(e).is_ok(),
                fields: Some(FieldOps {
                    infos: |world, e| world.get::<&T>(e).ok().map(|c| c.fields()),
                    get: |world, e, field| world.get::<&T>(e).ok().and_then(|c| c.get_field(field)),
                    set: |world, e, field, ron| {
                        // The registry verifies the component is present before
                        // calling, so this access cannot fail.
                        let mut c = world
                            .get::<&mut T>(e)
                            .expect("component present (checked by caller)");
                        c.set_field(field, ron)
                    },
                }),
                add_default: None,
            },
        );
    }

    /// Registers a reflected component type that can also be **added from a
    /// generic "Add Component" menu** — `T` must be `Default`, which supplies
    /// the value inserted on the entity.
    ///
    /// Equivalent to [`register_reflected`](Self::register_reflected) plus a
    /// zero-arg constructor. Use it for components a user can attach in the
    /// editor; use `register_reflected` for components that only exist
    /// implicitly (every entity already has them) or that have no sensible
    /// default.
    pub fn register_addable<T>(&mut self, name: &'static str)
    where
        T: Component + Serialize + DeserializeOwned + Reflect + Default,
    {
        self.register_reflected::<T>(name);
        if let Some(reflected) = self.types.get_mut(name) {
            reflected.add_default = Some(|world, e| {
                let _ = world.insert_one(e, T::default());
            });
        }
    }

    /// Removes the type registered under `name`. Returns whether it existed.
    pub fn unregister(&mut self, name: &str) -> bool {
        self.types.remove(name).is_some()
    }

    /// Whether a type is registered under `name`.
    pub fn is_registered(&self, name: &str) -> bool {
        self.types.contains_key(name)
    }

    /// The number of registered types.
    pub fn len(&self) -> usize {
        self.types.len()
    }

    /// Whether no types are registered.
    pub fn is_empty(&self) -> bool {
        self.types.is_empty()
    }

    /// The names of every registered type, sorted.
    pub fn names(&self) -> impl Iterator<Item = &'static str> + '_ {
        self.types.keys().copied()
    }

    /// Serializes the named component on `entity` to RON.
    ///
    /// # Errors
    /// [`UnknownType`](ReflectError::UnknownType) if the name is not registered,
    /// [`NoSuchEntity`](ReflectError::NoSuchEntity) if the entity is dead, or
    /// [`Missing`](ReflectError::Missing) if the entity lacks the component.
    pub fn get_ron(
        &self,
        world: &World,
        entity: Entity,
        type_name: &str,
    ) -> Result<String, ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Err(ReflectError::NoSuchEntity);
        }
        (reflected.get_ron)(world, entity)
            .ok_or_else(|| ReflectError::Missing(type_name.to_string()))
    }

    /// Parses `ron` into the named type and writes it onto `entity`, inserting
    /// the component if absent or replacing it if present.
    ///
    /// # Errors
    /// [`UnknownType`](ReflectError::UnknownType), [`NoSuchEntity`](ReflectError::NoSuchEntity),
    /// or [`Parse`](ReflectError::Parse) if the text is not valid for the type.
    pub fn set_ron(
        &self,
        world: &mut World,
        entity: Entity,
        type_name: &str,
        ron: &str,
    ) -> Result<(), ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Err(ReflectError::NoSuchEntity);
        }
        (reflected.set_ron)(world, entity, ron).map_err(|message| ReflectError::Parse {
            type_name: type_name.to_string(),
            message,
        })
    }

    /// Whether `entity` carries the named component.
    ///
    /// # Errors
    /// [`UnknownType`](ReflectError::UnknownType) if the name is not registered.
    pub fn has(
        &self,
        world: &World,
        entity: Entity,
        type_name: &str,
    ) -> Result<bool, ReflectError> {
        let reflected = self.lookup(type_name)?;
        Ok(world.contains(entity) && (reflected.has)(world, entity))
    }

    /// Removes the named component from `entity`. Returns whether it was present.
    ///
    /// # Errors
    /// [`UnknownType`](ReflectError::UnknownType) if the name is not registered.
    pub fn remove(
        &self,
        world: &mut World,
        entity: Entity,
        type_name: &str,
    ) -> Result<bool, ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Ok(false);
        }
        Ok((reflected.remove)(world, entity))
    }

    /// The names of all *registered* component types currently on `entity`,
    /// sorted. This is what a generic inspector iterates to show every editable
    /// component without knowing any concrete types.
    pub fn components_on(&self, world: &World, entity: Entity) -> Vec<&'static str> {
        if !world.contains(entity) {
            return Vec::new();
        }
        self.types
            .iter()
            .filter(|(_, r)| (r.has)(world, entity))
            .map(|(name, _)| *name)
            .collect()
    }

    /// Whether the named type was registered with per-field reflection
    /// ([`register_reflected`](Self::register_reflected)).
    pub fn is_reflected(&self, type_name: &str) -> bool {
        matches!(self.types.get(type_name), Some(r) if r.fields.is_some())
    }

    /// Registers a fieldless enum `E` under `name` (the syntactic type name its
    /// fields carry), so [`enum_variants`](Self::enum_variants) can list its
    /// values for an inspector dropdown. Independent of component registration —
    /// an enum is a field *type*, not a component.
    pub fn register_enum<E>(&mut self, name: &'static str)
    where
        E: ReflectEnum,
    {
        self.enums.insert(name, E::variants());
    }

    /// The variant names of an enum type registered with
    /// [`register_enum`](Self::register_enum), or `None` if the type name isn't
    /// a registered enum. The inspector renders a dropdown when this is `Some`.
    pub fn enum_variants(&self, type_name: &str) -> Option<&'static [&'static str]> {
        self.enums.get(type_name).copied()
    }

    /// Whether the named type can be added from a generic "Add Component" menu
    /// ([`register_addable`](Self::register_addable)).
    pub fn is_addable(&self, type_name: &str) -> bool {
        matches!(self.types.get(type_name), Some(r) if r.add_default.is_some())
    }

    /// The names of every addable component type, sorted — what an "Add
    /// Component" menu lists.
    pub fn addable_names(&self) -> impl Iterator<Item = &'static str> + '_ {
        self.types
            .iter()
            .filter(|(_, r)| r.add_default.is_some())
            .map(|(name, _)| *name)
    }

    /// Adds a default-constructed instance of the named component to `entity`,
    /// if the type is addable and the entity doesn't already carry it. Returns
    /// whether a component was inserted.
    ///
    /// # Errors
    /// [`UnknownType`](ReflectError::UnknownType) if the name isn't registered,
    /// or [`NoSuchEntity`](ReflectError::NoSuchEntity) if the entity is dead.
    pub fn add_default(
        &self,
        world: &mut World,
        entity: Entity,
        type_name: &str,
    ) -> Result<bool, ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Err(ReflectError::NoSuchEntity);
        }
        let Some(make) = reflected.add_default else {
            return Ok(false);
        };
        // Don't clobber an existing component — "add" is a no-op if present.
        if (reflected.has)(world, entity) {
            return Ok(false);
        }
        make(world, entity);
        Ok(true)
    }

    /// The field descriptors of the named component on `entity`.
    ///
    /// This is what a generic inspector iterates to render one widget per
    /// field. Returns [`NotReflected`](ReflectError::NotReflected) for types
    /// registered for whole-value access only.
    ///
    /// # Errors
    /// [`UnknownType`](ReflectError::UnknownType),
    /// [`NoSuchEntity`](ReflectError::NoSuchEntity),
    /// [`NotReflected`](ReflectError::NotReflected), or
    /// [`Missing`](ReflectError::Missing) if the entity lacks the component.
    pub fn field_infos(
        &self,
        world: &World,
        entity: Entity,
        type_name: &str,
    ) -> Result<&'static [FieldInfo], ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Err(ReflectError::NoSuchEntity);
        }
        let ops = reflected
            .fields
            .as_ref()
            .ok_or_else(|| ReflectError::NotReflected(type_name.to_string()))?;
        (ops.infos)(world, entity).ok_or_else(|| ReflectError::Missing(type_name.to_string()))
    }

    /// Serializes one field of the named component on `entity` to RON.
    ///
    /// # Errors
    /// As [`field_infos`](Self::field_infos), plus
    /// [`UnknownField`](ReflectError::UnknownField) if the type has no such
    /// field.
    pub fn get_field(
        &self,
        world: &World,
        entity: Entity,
        type_name: &str,
        field: &str,
    ) -> Result<String, ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Err(ReflectError::NoSuchEntity);
        }
        let ops = reflected
            .fields
            .as_ref()
            .ok_or_else(|| ReflectError::NotReflected(type_name.to_string()))?;
        if !(reflected.has)(world, entity) {
            return Err(ReflectError::Missing(type_name.to_string()));
        }
        (ops.get)(world, entity, field).ok_or_else(|| ReflectError::UnknownField(field.to_string()))
    }

    /// Parses `ron` into one field of the named component on `entity`.
    ///
    /// Only the named field changes; the rest of the component is untouched —
    /// this is the granularity an inspector edit needs.
    ///
    /// # Errors
    /// As [`field_infos`](Self::field_infos), plus
    /// [`UnknownField`](ReflectError::UnknownField) or
    /// [`FieldParse`](ReflectError::FieldParse).
    pub fn set_field(
        &self,
        world: &mut World,
        entity: Entity,
        type_name: &str,
        field: &str,
        ron: &str,
    ) -> Result<(), ReflectError> {
        let reflected = self.lookup(type_name)?;
        if !world.contains(entity) {
            return Err(ReflectError::NoSuchEntity);
        }
        let ops = reflected
            .fields
            .as_ref()
            .ok_or_else(|| ReflectError::NotReflected(type_name.to_string()))?;
        if !(reflected.has)(world, entity) {
            return Err(ReflectError::Missing(type_name.to_string()));
        }
        (ops.set)(world, entity, field, ron)
    }

    fn lookup(&self, type_name: &str) -> Result<&ReflectedType, ReflectError> {
        self.types
            .get(type_name)
            .ok_or_else(|| ReflectError::UnknownType(type_name.to_string()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::math::{Transform, Vec3};
    use crate::scene::{Node, Scene};
    use serde::Deserialize;

    fn registry() -> TypeRegistry {
        let mut r = TypeRegistry::new();
        r.register_reflected::<Transform>("Transform");
        r.register_reflected::<Node>("Node");
        r
    }

    #[test]
    fn registration_is_listed_and_sorted() {
        let r = registry();
        assert!(r.is_registered("Transform"));
        assert!(!r.is_registered("Nope"));
        assert_eq!(r.len(), 2);
        assert_eq!(r.names().collect::<Vec<_>>(), vec!["Node", "Transform"]);
    }

    #[test]
    fn get_then_set_round_trips_generically() {
        let r = registry();
        let mut scene = Scene::new();
        let e = scene.spawn(
            "thing",
            Transform::from_translation(Vec3::new(1.0, 2.0, 3.0)),
        );

        // Read generically (no Transform type named at this call site beyond the
        // string), then write it straight back.
        let ron = r.get_ron(scene.world(), e, "Transform").unwrap();
        r.set_ron(scene.world_mut(), e, "Transform", &ron).unwrap();

        // The value survived the round trip.
        let after = scene.local_transform(e).unwrap();
        assert!((after.translation - Vec3::new(1.0, 2.0, 3.0)).length() < 1e-6);
    }

    #[test]
    fn set_can_mutate_through_the_text() {
        let r = registry();
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);

        // Hand-edit the serialized form (as the inspector / a script would) and
        // apply it.
        let edited =
            ron::to_string(&Transform::from_translation(Vec3::new(5.0, 0.0, 0.0))).unwrap();
        r.set_ron(scene.world_mut(), e, "Transform", &edited)
            .unwrap();
        assert!((scene.local_transform(e).unwrap().translation.x - 5.0).abs() < 1e-6);
    }

    #[test]
    fn components_on_lists_present_registered_types() {
        let r = registry();
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY); // has Node + Transform
        assert_eq!(r.components_on(scene.world(), e), vec!["Node", "Transform"]);

        // Removing one drops it from the listing.
        assert!(r.remove(scene.world_mut(), e, "Transform").unwrap());
        assert_eq!(r.components_on(scene.world(), e), vec!["Node"]);
        assert!(!r.has(scene.world(), e, "Transform").unwrap());
    }

    #[test]
    fn errors_are_specific() {
        let r = registry();
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);

        // Unknown type name.
        assert!(matches!(
            r.get_ron(scene.world(), e, "Ghost"),
            Err(ReflectError::UnknownType(_))
        ));
        // Live entity missing the component.
        scene.world_mut().remove_one::<Node>(e).unwrap();
        assert!(matches!(
            r.get_ron(scene.world(), e, "Node"),
            Err(ReflectError::Missing(_))
        ));
        // Dead entity.
        let dead = scene.spawn("dead", Transform::IDENTITY);
        scene.despawn(dead, crate::scene::DespawnPolicy::Recursive);
        assert!(matches!(
            r.get_ron(scene.world(), dead, "Transform"),
            Err(ReflectError::NoSuchEntity)
        ));
        // Malformed RON.
        assert!(matches!(
            r.set_ron(scene.world_mut(), e, "Transform", "not valid ron"),
            Err(ReflectError::Parse { .. })
        ));
    }

    // --- Per-field reflection (`#[derive(Reflect)]`) ---

    /// A representative component: a mix of field types, a skipped public
    /// field, and a private field — exercises the derive's selection rules.
    #[derive(Reflect, Serialize, Deserialize, PartialEq, Debug)]
    struct Timer {
        pub repeating: bool,
        pub duration: f32,
        pub label: String,
        #[reflect(skip)]
        pub elapsed: f32,
        // Private: never reflected regardless of `skip`.
        _internal: u32,
    }

    impl Timer {
        fn sample() -> Self {
            Self {
                repeating: true,
                duration: 2.5,
                label: "tick".to_string(),
                elapsed: 1.0,
                _internal: 7,
            }
        }
    }

    /// A struct whose normalized fields carry slider ranges via the new
    /// `#[reflect(min, max)]` attribute. The inspector dispatches a `Slider`
    /// instead of a `DragValue` when both bounds are present.
    #[derive(Reflect, Serialize, Deserialize)]
    struct Knobs {
        #[reflect(min = 0.0, max = 1.0)]
        pub gain: f32,
        pub bias: f32,
    }

    #[derive(Reflect, Serialize, Deserialize)]
    struct Wrap(pub i32, pub bool);

    #[test]
    fn derive_supports_tuple_structs_with_positional_field_names() {
        // Tuple-struct field names round-trip as "0", "1", ... — matching
        // Rust's own positional accessors. Lets one-field newtype components
        // like `Layer(pub LayerMask)` reflect without a wrapper.
        let mut w = Wrap(42, false);
        let names: Vec<_> = w.fields().iter().map(|f| f.name).collect();
        assert_eq!(names, ["0", "1"]);
        assert_eq!(w.get_field("0").as_deref(), Some("42"));
        w.set_field("1", "true").unwrap();
        assert!(w.1);
    }

    #[test]
    fn derive_captures_min_max_attributes_as_field_range() {
        let k = Knobs {
            gain: 0.5,
            bias: 0.0,
        };
        let fields = k.fields();
        let gain = fields.iter().find(|f| f.name == "gain").unwrap();
        let bias = fields.iter().find(|f| f.name == "bias").unwrap();
        assert_eq!(gain.range, Some((0.0_f32, 1.0_f32)));
        assert_eq!(bias.range, None);
    }

    #[test]
    fn derive_lists_only_public_non_skipped_fields_in_order() {
        let t = Timer::sample();
        let names: Vec<_> = t.fields().iter().map(|f| f.name).collect();
        assert_eq!(names, ["repeating", "duration", "label"]);
        // Syntactic type names are preserved for inspector widget dispatch.
        let types: Vec<_> = t.fields().iter().map(|f| f.type_name).collect();
        assert_eq!(types, ["bool", "f32", "String"]);
    }

    #[test]
    fn derive_gets_each_field_as_ron() {
        let t = Timer::sample();
        assert_eq!(t.get_field("repeating").as_deref(), Some("true"));
        assert_eq!(t.get_field("duration").as_deref(), Some("2.5"));
        assert_eq!(t.get_field("label").as_deref(), Some("\"tick\""));
        // Skipped + private + unknown all read as None.
        assert_eq!(t.get_field("elapsed"), None);
        assert_eq!(t.get_field("_internal"), None);
        assert_eq!(t.get_field("nope"), None);
    }

    #[test]
    fn derive_sets_a_single_field_without_touching_others() {
        let mut t = Timer::sample();
        t.set_field("duration", "9.0").unwrap();
        t.set_field("repeating", "false").unwrap();
        assert_eq!(t.duration, 9.0);
        assert!(!t.repeating);
        // Other fields are untouched.
        assert_eq!(t.label, "tick");
        assert_eq!(t.elapsed, 1.0);
    }

    #[test]
    fn derive_set_reports_unknown_field_and_parse_errors() {
        let mut t = Timer::sample();
        assert!(matches!(
            t.set_field("elapsed", "0.0"), // public but skipped → not reflected
            Err(ReflectError::UnknownField(f)) if f == "elapsed"
        ));
        assert!(matches!(
            t.set_field("missing", "0.0"),
            Err(ReflectError::UnknownField(_))
        ));
        assert!(matches!(
            t.set_field("duration", "not a float"),
            Err(ReflectError::FieldParse { field, .. }) if field == "duration"
        ));
    }

    #[test]
    fn registry_lists_fields_of_a_reflected_component() {
        let r = registry();
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);
        assert!(r.is_reflected("Transform"));
        let names: Vec<_> = r
            .field_infos(scene.world(), e, "Transform")
            .unwrap()
            .iter()
            .map(|f| f.name)
            .collect();
        assert_eq!(names, ["translation", "rotation", "scale"]);
    }

    #[test]
    fn registry_gets_and_sets_one_field_through_the_world() {
        let r = registry();
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);

        // Set just the translation; rotation/scale stay identity. glam's Vec3
        // serializes as a tuple, so RON is `(1.0,2.0,3.0)`.
        r.set_field(
            scene.world_mut(),
            e,
            "Transform",
            "translation",
            "(1.0, 2.0, 3.0)",
        )
        .unwrap();
        let t = scene.world().get::<&Transform>(e).unwrap();
        assert_eq!(t.translation, Vec3::new(1.0, 2.0, 3.0));
        assert_eq!(t.scale, Vec3::ONE);
        drop(t);

        let got = r
            .get_field(scene.world(), e, "Transform", "translation")
            .unwrap();
        assert_eq!(got, "(1.0,2.0,3.0)");
    }

    #[test]
    fn registry_field_access_errors_are_specific() {
        let mut r = registry();
        // A whole-value-only type → NotReflected on field access.
        r.register::<TimerWhole>("TimerWhole");
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);
        scene.world_mut().insert_one(e, TimerWhole(1)).unwrap();

        assert!(!r.is_reflected("TimerWhole"));
        assert!(matches!(
            r.field_infos(scene.world(), e, "TimerWhole"),
            Err(ReflectError::NotReflected(_))
        ));
        // Unknown field on a reflected type.
        assert!(matches!(
            r.get_field(scene.world(), e, "Transform", "nope"),
            Err(ReflectError::UnknownField(_))
        ));
        // Reflected type, but the entity lacks the component.
        let bare = scene.spawn("bare", Transform::IDENTITY);
        scene.world_mut().remove_one::<Node>(bare).unwrap();
        assert!(matches!(
            r.get_field(scene.world(), bare, "Node", "name"),
            Err(ReflectError::Missing(_))
        ));
    }

    #[derive(Serialize, Deserialize)]
    struct TimerWhole(u32);

    // --- Enum reflection (`#[derive(ReflectEnum)]`) ---

    #[derive(ReflectEnum, Serialize, Deserialize, PartialEq, Debug)]
    enum Facing {
        North,
        East,
        South,
        West,
    }

    #[test]
    fn derive_enum_lists_variants_in_order() {
        assert_eq!(Facing::variants(), &["North", "East", "South", "West"]);
    }

    #[test]
    fn variant_names_round_trip_as_ron() {
        // The names ReflectEnum returns must be valid RON for the variant, so
        // the inspector can write a chosen name straight back through set_field.
        for name in Facing::variants() {
            let value: Facing = ron::from_str(name).unwrap();
            assert_eq!(&ron::to_string(&value).unwrap(), name);
        }
    }

    #[test]
    fn addable_component_can_be_added_by_name_and_listed() {
        use crate::render::MeshRenderer;
        let mut r = registry();
        r.register_addable::<MeshRenderer>("MeshRenderer");

        // Listed as addable; Transform (register_reflected) is not.
        assert!(r.is_addable("MeshRenderer"));
        assert!(!r.is_addable("Transform"));
        let addable: Vec<_> = r.addable_names().collect();
        assert_eq!(addable, ["MeshRenderer"]);

        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);
        assert!(!r.has(scene.world(), e, "MeshRenderer").unwrap());

        // First add inserts the default; a second add is a no-op (already there).
        assert!(r.add_default(scene.world_mut(), e, "MeshRenderer").unwrap());
        assert!(r.has(scene.world(), e, "MeshRenderer").unwrap());
        assert!(!r.add_default(scene.world_mut(), e, "MeshRenderer").unwrap());

        // Its enum field is editable as a registered enum.
        r.register_enum::<crate::render::PrimitiveShape>("PrimitiveShape");
        let shape = r
            .get_field(scene.world(), e, "MeshRenderer", "shape")
            .unwrap();
        assert_eq!(shape, "Cube"); // PrimitiveShape::default()
        assert_eq!(
            r.enum_variants("PrimitiveShape"),
            Some(["Cube", "Sphere", "Plane"].as_slice())
        );
    }

    #[test]
    fn non_addable_type_add_default_is_a_noop() {
        let r = registry(); // Transform/Node are register_reflected, not addable
        let mut scene = Scene::new();
        let e = scene.spawn("thing", Transform::IDENTITY);
        // Transform isn't addable → Ok(false), nothing inserted.
        assert!(!r.add_default(scene.world_mut(), e, "Transform").unwrap());
        // Unknown type → error.
        assert!(matches!(
            r.add_default(scene.world_mut(), e, "Ghost"),
            Err(ReflectError::UnknownType(_))
        ));
    }

    #[test]
    fn registry_lists_enum_variants_by_type_name() {
        let mut r = registry();
        r.register_enum::<Facing>("Facing");
        assert_eq!(
            r.enum_variants("Facing"),
            Some(["North", "East", "South", "West"].as_slice())
        );
        // Unregistered / non-enum type names return None.
        assert_eq!(r.enum_variants("Transform"), None);
        assert_eq!(r.enum_variants("Nope"), None);
    }

    #[test]
    fn derive_field_values_round_trip_through_get_then_set() {
        let original = Timer::sample();
        let mut clone = Timer {
            repeating: false,
            duration: 0.0,
            label: String::new(),
            elapsed: 0.0,
            _internal: 0,
        };
        for field in original.fields() {
            let ron = original.get_field(field.name).unwrap();
            clone.set_field(field.name, &ron).unwrap();
        }
        // Every reflected field now matches; non-reflected fields keep clone's.
        assert_eq!(clone.repeating, original.repeating);
        assert_eq!(clone.duration, original.duration);
        assert_eq!(clone.label, original.label);
        assert_eq!(clone.elapsed, 0.0);
    }
}
