// Idiomatic Rust layer - user-friendly types
// Package: {{ package_name }}
// Message: {{ message_name }}

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct {{ message_name }} {
    {% for field in fields %}
    {% if field.is_large_array %}#[cfg_attr(feature = "serde", serde(with = "serde_big_array::BigArray"))]
    {% endif %}pub {{ field.name }}: {{ field.rust_type }},
    {% endfor %}
}

impl {{ message_name }} {
    {% if !constants.is_empty() %}
    // Message constants (matches C++/Python conventions)
    {% for constant in constants %}
    pub const {{ constant.name }}: {{ constant.rust_type }} = {{ constant.value }};
    {% endfor %}

    {% endif %}
    pub fn new() -> Self {
        Self::default()
    }
}

impl Default for {{ message_name }} {
    fn default() -> Self {
        // Leverage RMW message's C init function to get correct default values
        <Self as crate::rosidl_runtime_rs::Message>::from_rmw_message(crate::msg::rmw::{{ message_name }}::default())
    }
}

// Reference-based conversions (idiomatic ↔ RMW)
impl From<&{{ message_name }}> for crate::msg::rmw::{{ message_name }} {
    #[allow(unused_variables)]
    fn from(idiomatic: &{{ message_name }}) -> Self {
        Self {
            {% for field in fields %}
            {% if field.is_bounded_wstring %}
            // String → rosidl_runtime_rs::BoundedWString<N> (use try_from)
            {{ field.name }}: crate::rosidl_runtime_rs::BoundedWString::try_from(idiomatic.{{ field.name }}.as_str()).unwrap(),
            {% else if field.is_wstring %}
            // String → rosidl_runtime_rs::WString
            {{ field.name }}: crate::rosidl_runtime_rs::WString::from(idiomatic.{{ field.name }}.as_str()),
            {% else if field.is_bounded_string %}
            // String → rosidl_runtime_rs::BoundedString<N> (use try_from)
            {{ field.name }}: crate::rosidl_runtime_rs::BoundedString::try_from(idiomatic.{{ field.name }}.as_str()).unwrap(),
            {% else if field.is_string %}
            // String → rosidl_runtime_rs::String (use rosidl_runtime_rs 0.5 API)
            {{ field.name }}: crate::rosidl_runtime_rs::String::from(idiomatic.{{ field.name }}.as_str()),
            {% else if field.is_bounded_sequence && field.is_primitive_sequence %}
            // Vec<primitive> → BoundedSequence<primitive> (use try_from)
            {{ field.name }}: crate::rosidl_runtime_rs::BoundedSequence::try_from(idiomatic.{{ field.name }}.clone()).unwrap(),
            {% else if field.is_bounded_sequence && field.is_unbounded_string_sequence %}
            // Vec<String> → BoundedSequence<rosidl_runtime_rs::String> (use try_from)
            {{ field.name }}: crate::rosidl_runtime_rs::BoundedSequence::try_from(
                idiomatic.{{ field.name }}.iter().map(|item| crate::rosidl_runtime_rs::String::from(item.as_str())).collect::<Vec<_>>()
            ).unwrap(),
            {% else if field.is_bounded_sequence && field.is_bounded_string_sequence %}
            // Vec<String> → BoundedSequence<rosidl_runtime_rs::BoundedString<N>> (use try_from)
            {{ field.name }}: crate::rosidl_runtime_rs::BoundedSequence::try_from(
                idiomatic.{{ field.name }}.iter().map(|item| crate::rosidl_runtime_rs::BoundedString::try_from(item.as_str()).unwrap()).collect::<Vec<_>>()
            ).unwrap(),
            {% else if field.is_bounded_sequence %}
            // Vec → BoundedSequence conversion with element conversion for nested messages (use try_from)
            {{ field.name }}: crate::rosidl_runtime_rs::BoundedSequence::try_from(
                idiomatic.{{ field.name }}.iter().map(|item| item.into()).collect::<Vec<_>>()
            ).unwrap(),
            {% else if field.is_primitive_sequence %}
            // Vec<primitive> → Sequence<primitive> (use rosidl_runtime_rs 0.5 API)
            {{ field.name }}: crate::rosidl_runtime_rs::Sequence::from(idiomatic.{{ field.name }}.clone()),
            {% else if field.is_unbounded_string_sequence %}
            // Vec<String> → Sequence<rosidl_runtime_rs::String>
            {{ field.name }}: crate::rosidl_runtime_rs::Sequence::from(
                idiomatic.{{ field.name }}.iter().map(|item| crate::rosidl_runtime_rs::String::from(item.as_str())).collect::<Vec<_>>()
            ),
            {% else if field.is_bounded_string_sequence %}
            // Vec<String> → Sequence<rosidl_runtime_rs::BoundedString<N>>
            {{ field.name }}: crate::rosidl_runtime_rs::Sequence::from(
                idiomatic.{{ field.name }}.iter().map(|item| crate::rosidl_runtime_rs::BoundedString::try_from(item.as_str()).unwrap()).collect::<Vec<_>>()
            ),
            {% else if field.is_sequence %}
            // Vec → Sequence conversion with element conversion for nested messages
            {{ field.name }}: crate::rosidl_runtime_rs::Sequence::from(
                idiomatic.{{ field.name }}.iter().map(|item| item.into()).collect::<Vec<_>>()
            ),
            {% else if field.is_unbounded_string_array %}
            // [String; N] → [rosidl_runtime_rs::String; N] with element conversion
            {{ field.name }}: std::array::from_fn(|i| crate::rosidl_runtime_rs::String::from(idiomatic.{{ field.name }}[i].as_str())),
            {% else if field.is_bounded_string_array %}
            // [String; N] → [rosidl_runtime_rs::BoundedString<M>; N] with element conversion
            {{ field.name }}: std::array::from_fn(|i| crate::rosidl_runtime_rs::BoundedString::try_from(idiomatic.{{ field.name }}[i].as_str()).unwrap()),
            {% else if field.is_nested_array %}
            // [NestedType; N] → [rmw::NestedType; N] with element conversion
            {{ field.name }}: std::array::from_fn(|i| (&idiomatic.{{ field.name }}[i]).into()),
            {% else if field.is_array %}
            // [primitive; N] arrays can be cloned directly
            {{ field.name }}: idiomatic.{{ field.name }}.clone(),
            {% else if field.is_primitive %}
            // Primitives are Copy, just copy the value
            {{ field.name }}: idiomatic.{{ field.name }},
            {% else %}
            // Nested messages need reference conversion
            {{ field.name }}: (&idiomatic.{{ field.name }}).into(),
            {% endif %}
            {% endfor %}
        }
    }
}

impl From<&crate::msg::rmw::{{ message_name }}> for {{ message_name }} {
    #[allow(unused_variables)]
    fn from(rmw: &crate::msg::rmw::{{ message_name }}) -> Self {
        Self {
            {% for field in fields %}
            {% if field.is_bounded_wstring %}
            // rosidl_runtime_rs::BoundedWString<N> → String
            {{ field.name }}: rmw.{{ field.name }}.to_string(),
            {% else if field.is_wstring %}
            // rosidl_runtime_rs::WString → String
            {{ field.name }}: rmw.{{ field.name }}.to_string(),
            {% else if field.is_bounded_string %}
            // rosidl_runtime_rs::BoundedString<N> → String
            {{ field.name }}: rmw.{{ field.name }}.to_string(),
            {% else if field.is_string %}
            // rosidl_runtime_rs::String → String (use rosidl_runtime_rs 0.5 API)
            {{ field.name }}: rmw.{{ field.name }}.to_string(),
            {% else if field.is_primitive_sequence %}
            // Sequence/BoundedSequence<primitive> → Vec<primitive> (use rosidl_runtime_rs 0.5 API)
            {{ field.name }}: rmw.{{ field.name }}.as_slice().to_vec(),
            {% else if field.is_unbounded_string_sequence %}
            // Sequence/BoundedSequence<rosidl_runtime_rs::String> → Vec<String>
            {{ field.name }}: rmw.{{ field.name }}.as_slice().iter().map(|item| item.to_string()).collect(),
            {% else if field.is_bounded_string_sequence %}
            // Sequence/BoundedSequence<rosidl_runtime_rs::BoundedString<N>> → Vec<String>
            {{ field.name }}: rmw.{{ field.name }}.as_slice().iter().map(|item| item.to_string()).collect(),
            {% else if field.is_sequence %}
            // Sequence/BoundedSequence → Vec conversion with element conversion for nested messages
            {{ field.name }}: rmw.{{ field.name }}.as_slice().iter().map(|item| item.into()).collect(),
            {% else if field.is_unbounded_string_array %}
            // [rosidl_runtime_rs::String; N] → [String; N] with element conversion
            {{ field.name }}: std::array::from_fn(|i| rmw.{{ field.name }}[i].to_string()),
            {% else if field.is_bounded_string_array %}
            // [rosidl_runtime_rs::BoundedString<M>; N] → [String; N] with element conversion
            {{ field.name }}: std::array::from_fn(|i| rmw.{{ field.name }}[i].to_string()),
            {% else if field.is_nested_array %}
            // [rmw::NestedType; N] → [NestedType; N] with element conversion
            {{ field.name }}: std::array::from_fn(|i| (&rmw.{{ field.name }}[i]).into()),
            {% else if field.is_array %}
            // [primitive; N] arrays can be cloned directly
            {{ field.name }}: rmw.{{ field.name }}.clone(),
            {% else if field.is_primitive %}
            // Primitives are Copy, just copy the value
            {{ field.name }}: rmw.{{ field.name }},
            {% else %}
            // Nested messages need reference conversion
            {{ field.name }}: (&rmw.{{ field.name }}).into(),
            {% endif %}
            {% endfor %}
        }
    }
}

// Owned conversions delegate to reference-based ones
impl From<crate::msg::rmw::{{ message_name }}> for {{ message_name }} {
    fn from(rmw: crate::msg::rmw::{{ message_name }}) -> Self {
        Self::from(&rmw)
    }
}

impl From<{{ message_name }}> for crate::msg::rmw::{{ message_name }} {
    fn from(idiomatic: {{ message_name }}) -> Self {
        Self::from(&idiomatic)
    }
}

// Message trait implementation for rosidl_runtime_rs
impl crate::rosidl_runtime_rs::Message for {{ message_name }} {
    type RmwMsg = crate::msg::rmw::{{ message_name }};

    fn into_rmw_message(msg_cow: std::borrow::Cow<'_, Self>) -> std::borrow::Cow<'_, Self::RmwMsg> {
        // Convert from idiomatic to RMW format
        std::borrow::Cow::Owned(msg_cow.into_owned().into())
    }

    fn from_rmw_message(msg: Self::RmwMsg) -> Self {
        // Convert from RMW to idiomatic format
        msg.into()
    }
}
