//! Field attribute parsing for `#[derive(State)]`.
//!
//! Parses `#[channel(LastValue)]`, `#[channel(Appender)]`, etc.
//! and `#[core]` annotations on struct fields.

use syn::{Attribute, Error, Ident, Result};

/// Channel merge strategy for a state field.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ChannelKind {
    /// Overwrite on update (default)
    LastValue,
    /// Overwrite on update, logs when overwritten (debug aid)
    BroadcastLast,
    /// Extend/append on update
    Appender,
    /// Overwrite on update, cleared between supersteps
    Ephemeral,
    /// Extend on update, cleared between supersteps
    Topic,
}

/// Parsed attributes for a single field.
#[derive(Debug)]
pub struct FieldAttrs {
    pub channel: ChannelKind,
    pub is_core: bool,
}

impl Default for FieldAttrs {
    fn default() -> Self {
        Self {
            channel: ChannelKind::LastValue,
            is_core: false,
        }
    }
}

/// Parse `#[channel(...)]` and `#[core]` attributes from a field's attribute list.
pub fn parse_field_attrs(attrs: &[Attribute]) -> Result<FieldAttrs> {
    let mut result = FieldAttrs::default();

    for attr in attrs {
        if attr.path().is_ident("core") {
            result.is_core = true;
        } else if attr.path().is_ident("channel") {
            let channel_ident: Ident = attr.parse_args()?;
            result.channel = match channel_ident.to_string().as_str() {
                "LastValue" => ChannelKind::LastValue,
                "BroadcastLast" => ChannelKind::BroadcastLast,
                "Appender" => ChannelKind::Appender,
                "Ephemeral" => ChannelKind::Ephemeral,
                "Topic" => ChannelKind::Topic,
                other => {
                    return Err(Error::new_spanned(
                        &channel_ident,
                        format!(
                            "unknown channel type `{other}`. \
                             Valid types: LastValue, BroadcastLast, Appender, Ephemeral, Topic"
                        ),
                    ));
                }
            };
        }
    }

    Ok(result)
}
