//! Priority type for the Qrusty client.
//!
//! Mirrors the server-side `Priority` enum, accepting either a numeric (`u64`)
//! or text (`String`) priority value.

use serde::{Deserialize, Serialize};

/// A message priority: either a numeric `u64` or a lexicographic `String`.
///
/// Serializes with `#[serde(untagged)]` so JSON looks like `"priority": 100`
/// or `"priority": "abc"` — matching the server's wire format.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Priority {
    Numeric(u64),
    Text(String),
}

impl Default for Priority {
    fn default() -> Self {
        Priority::Numeric(0)
    }
}

impl From<u64> for Priority {
    fn from(n: u64) -> Self {
        Priority::Numeric(n)
    }
}

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

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

impl std::fmt::Display for Priority {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Priority::Numeric(n) => write!(f, "{}", n),
            Priority::Text(s) => write!(f, "{}", s),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn serialize_numeric() {
        let p = Priority::Numeric(42);
        assert_eq!(serde_json::to_value(&p).unwrap(), serde_json::json!(42));
    }

    #[test]
    fn serialize_text() {
        let p = Priority::Text("alpha".to_owned());
        assert_eq!(
            serde_json::to_value(&p).unwrap(),
            serde_json::json!("alpha")
        );
    }

    #[test]
    fn deserialize_numeric() {
        let p: Priority = serde_json::from_value(serde_json::json!(100)).unwrap();
        assert_eq!(p, Priority::Numeric(100));
    }

    #[test]
    fn deserialize_text() {
        let p: Priority = serde_json::from_value(serde_json::json!("beta")).unwrap();
        assert_eq!(p, Priority::Text("beta".to_owned()));
    }

    #[test]
    fn default_is_numeric_zero() {
        assert_eq!(Priority::default(), Priority::Numeric(0));
    }

    #[test]
    fn from_u64() {
        let p: Priority = 99u64.into();
        assert_eq!(p, Priority::Numeric(99));
    }

    #[test]
    fn from_str() {
        let p: Priority = "gamma".into();
        assert_eq!(p, Priority::Text("gamma".to_owned()));
    }

    #[test]
    fn from_string() {
        let p: Priority = String::from("delta").into();
        assert_eq!(p, Priority::Text("delta".to_owned()));
    }

    #[test]
    fn display_numeric() {
        assert_eq!(Priority::Numeric(7).to_string(), "7");
    }

    #[test]
    fn display_text() {
        assert_eq!(Priority::Text("foo".to_owned()).to_string(), "foo");
    }

    #[test]
    fn round_trip_in_json_object() {
        let body = serde_json::json!({
            "queue": "test",
            "priority": Priority::Numeric(50),
            "payload": "hello"
        });
        assert_eq!(body["priority"], 50);

        let body = serde_json::json!({
            "queue": "test",
            "priority": Priority::Text("abc".to_owned()),
            "payload": "hello"
        });
        assert_eq!(body["priority"], "abc");
    }
}
