//! Request ID type definition.

use std::fmt;

use serde::{Deserialize, Serialize};

/// Opaque identifier for credential requests.
///
/// This type wraps the request ID returned by the IDP and provides
/// type safety to prevent mixing with other string identifiers.
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct RequestId(String);

impl RequestId {
    /// Create a new request ID.
    #[must_use]
    pub fn new(id: impl Into<String>) -> Self {
        Self(id.into())
    }

    /// Get the request ID as a string slice.
    #[must_use]
    pub fn as_str(&self) -> &str {
        &self.0
    }
}

impl fmt::Display for RequestId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

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

impl From<&str> for RequestId {
    fn from(s: &str) -> Self {
        Self::new(s)
    }
}

impl AsRef<str> for RequestId {
    fn as_ref(&self) -> &str {
        &self.0
    }
}

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

    #[test]
    fn test_request_id_new() {
        let id = RequestId::new("req_123");
        assert_eq!(id.as_str(), "req_123");
    }

    #[test]
    fn test_request_id_display() {
        let id = RequestId::new("req_abc");
        assert_eq!(format!("{id}"), "req_abc");
    }

    #[test]
    fn test_request_id_serialize() {
        let id = RequestId::new("req_test");
        let json = serde_json::to_string(&id).unwrap();
        assert_eq!(json, "\"req_test\"");
    }

    #[test]
    fn test_request_id_deserialize() {
        let id: RequestId = serde_json::from_str("\"req_test\"").unwrap();
        assert_eq!(id.as_str(), "req_test");
    }

    #[test]
    fn test_request_id_equality() {
        let id1 = RequestId::new("req_123");
        let id2 = RequestId::new("req_123");
        let id3 = RequestId::new("req_456");

        assert_eq!(id1, id2);
        assert_ne!(id1, id3);
    }
}
