use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};

/// A normalized browser event delivered to a LiveView.
///
/// # Examples
///
/// ```
/// use shelly::Event;
///
/// let mut event = Event::new("save_profile");
/// event.target = Some("profile-form".to_string());
///
/// assert_eq!(event.name, "save_profile");
/// assert_eq!(event.target.as_deref(), Some("profile-form"));
/// ```
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Event {
    /// Logical event name, for example `inc`, `save_profile`, or `validate`.
    pub name: String,

    /// Optional DOM target id or client-provided target scope.
    pub target: Option<String>,

    /// Event value. For forms, this is usually an object built from FormData.
    pub value: Value,

    /// Non-authoritative browser metadata.
    ///
    /// Treat this data as untrusted. Use it for diagnostics or UX hints, not
    /// authorization.
    #[serde(default)]
    pub metadata: Map<String, Value>,
}

impl Event {
    /// Create a simple event with `null` value and no metadata.
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            target: None,
            value: Value::Null,
            metadata: Map::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::Event;
    use serde_json::Value;

    #[test]
    fn event_new_defaults_to_null_value() {
        let event = Event::new("inc");
        assert_eq!(event.name, "inc");
        assert_eq!(event.value, Value::Null);
        assert!(event.target.is_none());
        assert!(event.metadata.is_empty());
    }
}
