// Trait-based Userdata system for Lua-rs
//
// Instead of using Lua's traditional metatable-based approach for userdata access,
// we leverage Rust's trait system for direct, type-safe dispatch of field access,
// method calls, and metamethods.
//
// Key design principles:
// 1. Trait-based dispatch (no metatable lookup for known operations)
// 2. Auto-derive from Rust structs via `#[derive(LuaUserData)]`
// 3. Automatic metamethod generation from Rust trait impls (Display → __tostring, Ord → __lt, etc.)
// 4. Backward compatibility via `as_any()` downcasting
// 5. Metatables still work as fallback for Lua-level customization

use std::any::Any;
use std::fmt;

use crate::lua_vm::CFunction;

/// Intermediate value type for userdata field/method returns.
///
/// Since `LuaValue` requires GC-allocated strings, trait methods return `UdValue`
/// which the VM converts to proper `LuaValue` (interning strings as needed).
pub enum UdValue {
    Nil,
    Boolean(bool),
    Integer(i64),
    Number(f64),
    /// A Rust string — will be interned by the VM when converting to LuaValue
    Str(String),
    /// A light C function — used for returning methods from `get_field`
    Function(CFunction),
    /// Borrowed reference to another userdata's inner value (as operand in
    /// arithmetic/comparison). Valid only during the trait method call.
    /// Use [`UdValue::as_userdata_ref`] to safely downcast.
    UserdataRef(*const dyn Any),
    /// Owned userdata value (as return from arithmetic trait methods).
    /// The VM allocates this as a new GC-managed userdata.
    UserdataOwned(Box<dyn UserDataTrait>),
}

impl Clone for UdValue {
    fn clone(&self) -> Self {
        match self {
            UdValue::Nil => UdValue::Nil,
            UdValue::Boolean(b) => UdValue::Boolean(*b),
            UdValue::Integer(i) => UdValue::Integer(*i),
            UdValue::Number(n) => UdValue::Number(*n),
            UdValue::Str(s) => UdValue::Str(s.clone()),
            UdValue::Function(f) => UdValue::Function(*f),
            UdValue::UserdataRef(p) => UdValue::UserdataRef(*p),
            UdValue::UserdataOwned(_) => {
                // Cannot clone owned userdata — return Nil as fallback.
                // This should not happen in practice; the VM consumes owned
                // userdata immediately.
                UdValue::Nil
            }
        }
    }
}

impl UdValue {
    #[inline]
    pub fn is_nil(&self) -> bool {
        matches!(self, UdValue::Nil)
    }

    /// Try to downcast a `UserdataRef` operand to a concrete type.
    ///
    /// Returns `Some(&T)` if the operand is a userdata of type `T`.
    /// This is the primary way to access the other operand in arithmetic
    /// trait methods when both operands are userdata.
    ///
    /// # Safety
    /// The returned reference borrows from the GC-managed userdata on the
    /// Lua stack. It is valid for the duration of the trait method call.
    ///
    /// # Example (generated by derive macro)
    /// ```ignore
    /// fn lua_add(&self, other: &UdValue) -> Option<UdValue> {
    ///     if let Some(o) = other.as_userdata_ref::<Vec2>() {
    ///         Some(UdValue::from_userdata(Vec2 { x: self.x + o.x, y: self.y + o.y }))
    ///     } else {
    ///         None
    ///     }
    /// }
    /// ```
    #[inline]
    pub fn as_userdata_ref<T: 'static>(&self) -> Option<&T> {
        match self {
            UdValue::UserdataRef(ptr) => {
                // SAFETY: The pointer originates from a GC-managed userdata that
                // is alive on the Lua stack during this call. The VM guarantees
                // the pointer remains valid for the duration of the trait method.
                let any_ref: &dyn Any = unsafe { &**ptr };
                any_ref.downcast_ref::<T>()
            }
            _ => None,
        }
    }

    /// Wrap a value that implements `UserDataTrait` into an owned `UdValue`.
    ///
    /// Use this as the return value from arithmetic trait methods when the
    /// result is a new userdata (e.g., `Vec2 + Vec2 → Vec2`).
    #[inline]
    pub fn from_userdata<T: UserDataTrait>(value: T) -> Self {
        UdValue::UserdataOwned(Box::new(value))
    }
}

/// Describes how a userdata type can be accessed from Lua.
///
/// This trait provides rich, typed access to struct fields, methods, and standard
/// operations. The `#[derive(LuaUserData)]` macro auto-implements this trait by
/// exposing public fields for structs, or by creating a fieldless userdata facade for
/// enums and tuple/unit structs. Methods are exposed via `#[lua_methods]` attribute macro
/// on impl blocks, which generates static C wrapper functions returned from `get_field`
/// as `UdValue::Function(cfunction)`.
///
/// # Dispatch priority (when Lua accesses `obj.key`):
/// 1. `get_field(key)` — field or method access (fields return value, methods return CFunction)
/// 2. Metatable `__index` — traditional Lua fallback
///
/// # Example (manual implementation)
/// ```ignore
/// struct Point { x: f64, y: f64 }
///
/// impl UserDataTrait for Point {
///     fn type_name(&self) -> &'static str { "Point" }
///
///     fn get_field(&self, key: &str) -> Option<UdValue> {
///         match key {
///             "x" => Some(UdValue::Number(self.x)),
///             "y" => Some(UdValue::Number(self.y)),
///             _ => None,
///         }
///     }
///
///     fn set_field(&mut self, key: &str, value: UdValue) -> Option<Result<(), String>> {
///         match key {
///             "x" => match value {
///                 UdValue::Number(n) => { self.x = n; Some(Ok(())) }
///                 _ => Some(Err("x must be a number".into()))
///             }
///             _ => None,
///         }
///     }
///
///     fn as_any(&self) -> &dyn Any { self }
///     fn as_any_mut(&mut self) -> &mut dyn Any { self }
/// }
/// ```
pub trait UserDataTrait: 'static {
    // ==================== Identity ====================

    /// Returns the type name displayed in error messages and `type()` calls.
    /// For derive macro: uses the struct name.
    fn type_name(&self) -> &'static str;

    // ==================== Field Access ====================

    /// Get a field value by name.
    /// Returns `Some(value)` if the field exists, `None` to fall through to metatable.
    fn get_field(&self, _key: &str) -> Option<UdValue> {
        None
    }

    /// Set a field value by name.
    /// Returns:
    /// - `Some(Ok(()))` — field was set successfully
    /// - `Some(Err(msg))` — field exists but value is invalid (type mismatch, etc.)
    /// - `None` — field not found, fall through to metatable `__newindex`
    fn set_field(&mut self, _key: &str, _value: UdValue) -> Option<Result<(), String>> {
        None
    }

    // ==================== Metamethods ====================
    // These are auto-generated by the derive macro when the struct
    // implements the corresponding Rust trait. Return None = not supported.

    /// `__tostring`: String representation.
    /// Auto-generated when struct implements `Display`.
    fn lua_tostring(&self) -> Option<String> {
        None
    }

    /// `__eq`: Equality comparison.
    /// Auto-generated when struct implements `PartialEq`.
    /// `other` is guaranteed to be a `&dyn UserDataTrait` — downcast via `as_any()`.
    fn lua_eq(&self, _other: &dyn UserDataTrait) -> Option<bool> {
        None
    }

    /// `__lt`: Less-than comparison.
    /// Auto-generated when struct implements `PartialOrd`.
    fn lua_lt(&self, _other: &dyn UserDataTrait) -> Option<bool> {
        None
    }

    /// `__le`: Less-or-equal comparison.
    /// Auto-generated when struct implements `PartialOrd`.
    fn lua_le(&self, _other: &dyn UserDataTrait) -> Option<bool> {
        None
    }

    /// `__len`: Length operator (`#obj`).
    /// Auto-generated when struct has a `.len()` method.
    fn lua_len(&self) -> Option<UdValue> {
        None
    }

    /// `__unm`: Unary minus (`-obj`).
    /// Auto-generated when struct implements `Neg`.
    fn lua_unm(&self) -> Option<UdValue> {
        None
    }

    /// `__add`: Addition (`obj + other`).
    /// Auto-generated when struct implements `Add`.
    fn lua_add(&self, _other: &UdValue) -> Option<UdValue> {
        None
    }

    /// `__sub`: Subtraction (`obj - other`).
    /// Auto-generated when struct implements `Sub`.
    fn lua_sub(&self, _other: &UdValue) -> Option<UdValue> {
        None
    }

    /// `__mul`: Multiplication (`obj * other`).
    /// Auto-generated when struct implements `Mul`.
    fn lua_mul(&self, _other: &UdValue) -> Option<UdValue> {
        None
    }

    /// `__div`: Division (`obj / other`).
    /// Auto-generated when struct implements `Div`.
    fn lua_div(&self, _other: &UdValue) -> Option<UdValue> {
        None
    }

    /// `__mod`: Modulo (`obj % other`).
    /// Auto-generated when struct implements `Rem`.
    fn lua_mod(&self, _other: &UdValue) -> Option<UdValue> {
        None
    }

    /// `__concat`: Concatenation (`obj .. other`).
    fn lua_concat(&self, _other: &UdValue) -> Option<UdValue> {
        None
    }

    /// `__gc`: Called when the userdata is garbage collected.
    /// Use this for cleanup (closing files, releasing resources, etc.).
    fn lua_gc(&mut self) {}

    /// `__close`: Called when a to-be-closed variable goes out of scope.
    fn lua_close(&mut self) {}

    /// `__call`: Makes the userdata callable like a function.
    ///
    /// Return `Some(cfunction)` to make `obj(args...)` work from Lua.
    /// The CFunction receives `self` (the userdata) as arg 1, followed by
    /// the caller's arguments.
    ///
    /// This is checked before the metatable `__call` fallback.
    ///
    /// # Example
    /// ```ignore
    /// fn lua_call(&self) -> Option<CFunction> {
    ///     fn call_impl(l: &mut LuaState) -> LuaResult<usize> {
    ///         let ud = l.get_arg(1).unwrap();
    ///         let x = l.get_arg(2).and_then(|v| v.as_integer()).unwrap_or(0);
    ///         l.push_value(LuaValue::integer(x * 2))?;
    ///         Ok(1)
    ///     }
    ///     Some(call_impl)
    /// }
    /// ```
    fn lua_call(&self) -> Option<crate::lua_vm::CFunction> {
        None
    }

    // ==================== Iteration ====================

    /// Stateless iterator: given the current control variable, return the next
    /// `(control, value)` pair, or `None` to stop.
    ///
    /// This follows Lua's generic-for protocol:
    /// ```lua
    /// for k, v in pairs(ud) do ... end
    /// ```
    ///
    /// The control variable starts as `UdValue::Nil`. Implementors decide
    /// what it represents (e.g., an integer index for sequences).
    ///
    /// # Example (Vec-like)
    /// ```ignore
    /// fn lua_next(&self, control: &UdValue) -> Option<(UdValue, UdValue)> {
    ///     let idx = match control {
    ///         UdValue::Nil => 0,
    ///         UdValue::Integer(i) => *i as usize,
    ///         _ => return None,
    ///     };
    ///     self.items.get(idx).map(|v| (
    ///         UdValue::Integer((idx + 1) as i64),
    ///         UdValue::Integer(*v as i64),
    ///     ))
    /// }
    /// ```
    fn lua_next(&self, _control: &UdValue) -> Option<(UdValue, UdValue)> {
        None
    }

    // ==================== Reflection ====================

    /// List available field names (for debugging, iteration, auto-completion).
    fn field_names(&self) -> &'static [&'static str] {
        &[]
    }

    // ==================== Downcasting ====================
    // Required for backward compatibility and type-specific access.
    // The derive macro auto-generates these.

    /// Downcast to `&dyn Any` for type-specific access.
    fn as_any(&self) -> &dyn Any;

    /// Downcast to `&mut dyn Any` for mutable type-specific access.
    fn as_any_mut(&mut self) -> &mut dyn Any;
}

// ==================== UdValue ↔ Rust type conversions ====================

impl From<bool> for UdValue {
    fn from(b: bool) -> Self {
        UdValue::Boolean(b)
    }
}

impl From<i64> for UdValue {
    fn from(i: i64) -> Self {
        UdValue::Integer(i)
    }
}

impl From<i32> for UdValue {
    fn from(i: i32) -> Self {
        UdValue::Integer(i as i64)
    }
}

impl From<f64> for UdValue {
    fn from(n: f64) -> Self {
        UdValue::Number(n)
    }
}

impl From<f32> for UdValue {
    fn from(n: f32) -> Self {
        UdValue::Number(n as f64)
    }
}

impl From<String> for UdValue {
    fn from(s: String) -> Self {
        UdValue::Str(s)
    }
}

impl From<&str> for UdValue {
    fn from(s: &str) -> Self {
        UdValue::Str(s.to_owned())
    }
}

impl<T: Into<UdValue>> From<Option<T>> for UdValue {
    fn from(opt: Option<T>) -> Self {
        match opt {
            Some(v) => v.into(),
            None => UdValue::Nil,
        }
    }
}

// ==================== UdValue → Rust type extraction ====================

impl UdValue {
    /// Extract as bool. Follows Lua truthiness: nil and false are false, everything else is true.
    pub fn to_bool(&self) -> bool {
        match self {
            UdValue::Nil => false,
            UdValue::Boolean(b) => *b,
            _ => true,
        }
    }

    /// Extract as i64 (with optional float→int coercion).
    pub fn to_integer(&self) -> Option<i64> {
        match self {
            UdValue::Integer(i) => Some(*i),
            UdValue::Number(n) => {
                let i = *n as i64;
                if (i as f64) == *n { Some(i) } else { None }
            }
            _ => None,
        }
    }

    /// Extract as f64 (with optional int→float coercion).
    pub fn to_number(&self) -> Option<f64> {
        match self {
            UdValue::Number(n) => Some(*n),
            UdValue::Integer(i) => Some(*i as f64),
            _ => None,
        }
    }

    /// Extract as string reference.
    pub fn to_str(&self) -> Option<&str> {
        match self {
            UdValue::Str(s) => Some(s.as_str()),
            _ => None,
        }
    }
}

impl fmt::Debug for UdValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UdValue::Nil => write!(f, "Nil"),
            UdValue::Boolean(b) => write!(f, "Boolean({})", b),
            UdValue::Integer(i) => write!(f, "Integer({})", i),
            UdValue::Number(n) => write!(f, "Number({})", n),
            UdValue::Str(s) => write!(f, "Str({:?})", s),
            UdValue::Function(_) => write!(f, "Function(<cfunction>)"),
            UdValue::UserdataRef(_) => write!(f, "UserdataRef(<ptr>)"),
            UdValue::UserdataOwned(ud) => write!(f, "UserdataOwned({})", ud.type_name()),
        }
    }
}

impl fmt::Display for UdValue {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            UdValue::Nil => write!(f, "nil"),
            UdValue::Boolean(b) => write!(f, "{}", b),
            UdValue::Integer(i) => write!(f, "{}", i),
            UdValue::Number(n) => write!(f, "{}", n),
            UdValue::Str(s) => write!(f, "{}", s),
            UdValue::Function(_) => write!(f, "function"),
            UdValue::UserdataRef(_) => write!(f, "userdata"),
            UdValue::UserdataOwned(ud) => write!(f, "{}", ud.type_name()),
        }
    }
}

// ==================== UdValue ↔ LuaValue conversion ====================

/// Convert a `UdValue` to a `LuaValue`.
///
/// Most variants are zero-cost. `UdValue::Str` requires GC allocation via `LuaState`.
/// This is the bridge between trait-based dispatch (which returns `UdValue`) and the
/// VM's internal representation (`LuaValue`).
pub fn udvalue_to_lua_value(
    lua_state: &mut crate::lua_vm::LuaState,
    udv: UdValue,
) -> crate::lua_vm::LuaResult<crate::lua_value::LuaValue> {
    use crate::lua_value::LuaValue;
    match udv {
        UdValue::Nil => Ok(LuaValue::nil()),
        UdValue::Boolean(b) => Ok(LuaValue::boolean(b)),
        UdValue::Integer(i) => Ok(LuaValue::integer(i)),
        UdValue::Number(n) => Ok(LuaValue::float(n)),
        UdValue::Str(s) => lua_state.create_string(&s),
        UdValue::Function(f) => Ok(LuaValue::cfunction(f)),
        UdValue::UserdataRef(_) => Ok(LuaValue::nil()), // should not be returned
        UdValue::UserdataOwned(ud) => {
            use crate::lua_value::LuaUserdata;
            let userdata = LuaUserdata::from_boxed(ud);
            lua_state.create_userdata(userdata)
        }
    }
}

/// Convert a `LuaValue` to a `UdValue`.
///
/// Lossless for nil, bool, int, float, string. Other types (table, function, etc.)
/// become `UdValue::Nil` since they can't be represented in the trait world.
pub fn lua_value_to_udvalue(value: &crate::lua_value::LuaValue) -> UdValue {
    if value.is_nil() {
        UdValue::Nil
    } else if let Some(b) = value.as_boolean() {
        UdValue::Boolean(b)
    } else if let Some(i) = value.as_integer() {
        UdValue::Integer(i)
    } else if let Some(n) = value.as_float() {
        UdValue::Number(n)
    } else if let Some(s) = value.as_str() {
        UdValue::Str(s.to_owned())
    } else if let Some(ud) = value.as_userdata_mut() {
        // Carry userdata reference so arithmetic trait methods can downcast
        UdValue::UserdataRef(ud.get_trait().as_any() as *const dyn Any)
    } else {
        UdValue::Nil
    }
}

// ==================== Convenience macro for simple types ====================

/// Implement `UserDataTrait` for types that only need type name and downcast support.
/// These types use metatables for their Lua-visible API (e.g., IO file handles).
///
/// ```ignore
/// impl_simple_userdata!(LuaFile, "FILE*");
/// ```
#[macro_export]
macro_rules! impl_simple_userdata {
    ($ty:ty, $name:expr) => {
        impl $crate::lua_value::userdata_trait::UserDataTrait for $ty {
            fn type_name(&self) -> &'static str {
                $name
            }

            fn as_any(&self) -> &dyn std::any::Any {
                self
            }

            fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
                self
            }
        }
    };
}

// ==================== Method Provider ====================

/// Blanket trait providing a default no-op method lookup.
///
/// When `#[lua_methods]` attribute macro is used on an impl block,
/// it generates an inherent `__lua_lookup_method` function on the type
/// that shadows this trait's default. The derive macro's `get_field`
/// calls `Self::__lua_lookup_method(key)` which resolves to the
/// inherent method (if defined) or falls back to this default.
pub trait LuaMethodProvider {
    fn __lua_lookup_method(_key: &str) -> Option<CFunction> {
        None
    }
}

impl<T> LuaMethodProvider for T {}

// ==================== Type Registration ====================

/// Blanket trait providing a default empty static methods list.
///
/// When `#[lua_methods]` is used on an impl block that contains associated
/// functions (no `self`), it generates an inherent `__lua_static_methods()`
/// function on the type that shadows this trait's default.
///
/// Used by `LuaState::register_type::<T>(name)` to populate the class table.
pub trait LuaStaticMethodProvider {
    fn __lua_static_methods() -> &'static [(&'static str, CFunction)] {
        &[]
    }
}

impl<T> LuaStaticMethodProvider for T {}

/// Trait for types that can be registered with Lua via `register_type_of::<T>`.
///
/// This trait is explicitly implemented by `#[lua_methods]` (no blanket impl),
/// so `T::lua_static_methods()` dispatches to the actual generated methods.
///
/// Unlike `LuaStaticMethodProvider` (which has a blanket impl that always
/// returns `&[]`), this trait guarantees that the type has real method info.
pub trait LuaRegistrable {
    /// Return all static (associated) methods for type registration.
    fn lua_static_methods() -> &'static [(&'static str, CFunction)];
}

// ==================== Enum Export ====================

/// Trait for Rust enums that can be exported to Lua as a table of constants.
///
/// Automatically implemented by `#[derive(LuaUserData)]` on C-like enums
/// (enums with no data fields). Each variant becomes a key-value pair in
/// a Lua table.
///
/// # Example
///
/// ```ignore
/// #[derive(LuaUserData)]
/// enum Color {
///     Red,    // 0
///     Green,  // 1
///     Blue,   // 2
/// }
///
/// // With explicit discriminants:
/// #[derive(LuaUserData)]
/// enum HttpStatus {
///     Ok = 200,
///     NotFound = 404,
///     ServerError = 500,
/// }
///
/// // Register in Lua:
/// vm.register_enum::<Color>("Color")?;
/// // Lua: Color.Red == 0, Color.Green == 1, Color.Blue == 2
/// ```
pub trait LuaEnum {
    /// Return variant name-value pairs for Lua table construction.
    fn variants() -> &'static [(&'static str, i64)];

    /// Return the enum's type name.
    fn enum_name() -> &'static str;
}

// ==================== OpaqueUserData ====================

/// Wraps any `T: 'static` as an opaque Lua userdata.
///
/// No fields, methods, or metamethods are exposed — the value is a "black box"
/// in Lua. From Rust you can recover the original type via `downcast_ref::<T>()`.
///
/// Use [`LuaVM::push_any`] to create one conveniently.
///
/// # Example
///
/// ```ignore
/// // Third-party type you don't control
/// let client = reqwest::Client::new();
/// let ud = vm.push_any(client)?;
/// vm.set_global("http_client", ud)?;
///
/// // Later, in a Rust callback:
/// let client = ud_value.downcast_ref::<reqwest::Client>().unwrap();
/// ```
pub struct OpaqueUserData<T: 'static> {
    value: T,
}

impl<T: 'static> OpaqueUserData<T> {
    /// Wrap a value.
    pub fn new(value: T) -> Self {
        OpaqueUserData { value }
    }

    /// Get a reference to the inner value.
    pub fn inner(&self) -> &T {
        &self.value
    }

    /// Get a mutable reference to the inner value.
    pub fn inner_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T: 'static> UserDataTrait for OpaqueUserData<T> {
    fn type_name(&self) -> &'static str {
        std::any::type_name::<T>()
    }

    fn as_any(&self) -> &dyn Any {
        // Downcast to T (not OpaqueUserData<T>) for ergonomic access
        &self.value
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        &mut self.value
    }
}

// ==================== RefUserData — zero-cost borrowed reference ====================

/// A userdata wrapper that holds a raw pointer to an external `T: UserDataTrait`.
///
/// This enables passing Rust objects to Lua **by reference** without transferring
/// ownership. The object lives on the Rust side; Lua sees a full userdata with
/// field access, method calls, and metamethods — all forwarded through the pointer.
///
/// # Performance
/// Zero overhead compared to owned userdata — no `Rc`, no `RefCell`, no
/// atomic operations. The pointer is dereferenced directly on every access.
///
/// # Safety
/// The caller **must** guarantee that the pointee outlives every Lua access.
/// Accessing the userdata after the Rust object is dropped is undefined behavior.
/// This is deliberately an `unsafe` API — the same contract as C Lua's light
/// userdata, but with full trait-based dispatch.
///
/// # Example
/// ```ignore
/// let mut player = Player::new("Alice", 100);
///
/// // Lend to Lua (no ownership transfer)
/// let ud_val = state.create_userdata_ref(&mut player)?;
/// state.set_global("player", ud_val)?;
///
/// // Lua can read/write fields, call methods — all forwarded to `player`
/// state.execute_string(r#"
///     print(player.name)      -- "Alice"
///     player:take_damage(10)
///     print(player.hp)        -- 90
/// "#)?;
///
/// // Back in Rust, `player` reflects the mutations
/// assert_eq!(player.hp, 90);
/// ```
pub struct RefUserData<T: UserDataTrait> {
    ptr: *mut T,
}

impl<T: UserDataTrait> RefUserData<T> {
    /// Create a `RefUserData` from a mutable reference.
    ///
    /// # Safety
    /// The referenced object must outlive all Lua accesses to this userdata.
    #[inline]
    pub unsafe fn new(reference: &mut T) -> Self {
        RefUserData {
            ptr: reference as *mut T,
        }
    }

    /// Create from a raw pointer.
    ///
    /// # Safety
    /// The pointer must be valid and properly aligned for the entire duration
    /// that Lua can access this userdata.
    #[inline]
    pub unsafe fn from_raw(ptr: *mut T) -> Self {
        RefUserData { ptr }
    }

    #[inline]
    fn inner(&self) -> &T {
        unsafe { &*self.ptr }
    }

    #[inline]
    fn inner_mut(&mut self) -> &mut T {
        unsafe { &mut *self.ptr }
    }
}

/// Forward every `UserDataTrait` method to the pointee.
///
/// This is intentionally not `'static` on `T` alone — the `'static` bound
/// comes from `UserDataTrait: 'static`. The raw pointer erases the lifetime;
/// correctness relies on the caller's safety guarantee.
impl<T: UserDataTrait> UserDataTrait for RefUserData<T> {
    #[inline]
    fn type_name(&self) -> &'static str {
        self.inner().type_name()
    }

    #[inline]
    fn get_field(&self, key: &str) -> Option<UdValue> {
        self.inner().get_field(key)
    }

    #[inline]
    fn set_field(&mut self, key: &str, value: UdValue) -> Option<Result<(), String>> {
        self.inner_mut().set_field(key, value)
    }

    fn lua_tostring(&self) -> Option<String> {
        self.inner().lua_tostring()
    }

    fn lua_eq(&self, other: &dyn UserDataTrait) -> Option<bool> {
        self.inner().lua_eq(other)
    }

    fn lua_lt(&self, other: &dyn UserDataTrait) -> Option<bool> {
        self.inner().lua_lt(other)
    }

    fn lua_le(&self, other: &dyn UserDataTrait) -> Option<bool> {
        self.inner().lua_le(other)
    }

    fn lua_len(&self) -> Option<UdValue> {
        self.inner().lua_len()
    }

    fn lua_unm(&self) -> Option<UdValue> {
        self.inner().lua_unm()
    }

    fn lua_add(&self, other: &UdValue) -> Option<UdValue> {
        self.inner().lua_add(other)
    }

    fn lua_sub(&self, other: &UdValue) -> Option<UdValue> {
        self.inner().lua_sub(other)
    }

    fn lua_mul(&self, other: &UdValue) -> Option<UdValue> {
        self.inner().lua_mul(other)
    }

    fn lua_div(&self, other: &UdValue) -> Option<UdValue> {
        self.inner().lua_div(other)
    }

    fn lua_mod(&self, other: &UdValue) -> Option<UdValue> {
        self.inner().lua_mod(other)
    }

    fn lua_concat(&self, other: &UdValue) -> Option<UdValue> {
        self.inner().lua_concat(other)
    }

    fn lua_gc(&mut self) {
        // Intentionally a no-op: we don't own the data, so GC must not drop it.
    }

    fn lua_close(&mut self) {
        // Same: no-op for borrowed references.
    }

    fn field_names(&self) -> &'static [&'static str] {
        self.inner().field_names()
    }

    fn as_any(&self) -> &dyn Any {
        self.inner().as_any()
    }

    fn as_any_mut(&mut self) -> &mut dyn Any {
        self.inner_mut().as_any_mut()
    }
}
