//! Resource content type for MCP resources/read responses
//!
//! ResourceContent automatically includes uri and mimeType fields as required
//! by the MCP spec for resources/read responses.

use serde::Serialize;
use serde_json::Value;

use super::annotations::Annotations;
use super::types::Content;

/// Resource content for MCP resources/read responses
///
/// Automatically includes uri and mimeType per MCP spec.
/// Use this type for Resource::read() return values.
///
/// # Examples
///
/// ```rust,ignore
/// // Simple text resource
/// ResourceContent::text("file:///path", "content here")
///
/// // With specific MIME type
/// ResourceContent::text("file:///path", "content")
///     .with_mime_type("application/json")
///
/// // Binary resource
/// ResourceContent::blob("file:///path", base64_data, "image/png")
/// ```
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ResourceContent {
    /// Resource URI (required)
    pub uri: String,

    /// MIME type
    #[serde(skip_serializing_if = "Option::is_none")]
    pub mime_type: Option<String>,

    /// Text content (mutually exclusive with blob)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub text: Option<String>,

    /// Binary content as base64 (mutually exclusive with text)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub blob: Option<String>,
}

impl ResourceContent {
    /// Create a text resource with default text/plain MIME type
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// let content = ResourceContent::text("file:///doc.txt", "Hello, world!");
    /// ```
    pub fn text(uri: impl Into<String>, text: impl Into<String>) -> Self {
        Self {
            uri: uri.into(),
            mime_type: Some("text/plain".to_string()),
            text: Some(text.into()),
            blob: None,
        }
    }

    /// Set or override the MIME type
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// let content = ResourceContent::text("file:///data.json", json_string)
    ///     .with_mime_type("application/json");
    /// ```
    pub fn with_mime_type(mut self, mime_type: impl Into<String>) -> Self {
        self.mime_type = Some(mime_type.into());
        self
    }

    /// Create a binary resource with base64-encoded data
    ///
    /// # Examples
    ///
    /// ```rust,ignore
    /// let content = ResourceContent::blob(
    ///     "file:///image.png",
    ///     base64_data,
    ///     "image/png"
    /// );
    /// ```
    pub fn blob(
        uri: impl Into<String>,
        data: impl Into<String>,
        mime_type: impl Into<String>,
    ) -> Self {
        Self {
            uri: uri.into(),
            mime_type: Some(mime_type.into()),
            text: None,
            blob: Some(data.into()),
        }
    }
}

impl Content for ResourceContent {
    fn content_type(&self) -> &'static str {
        "resource"
    }

    fn to_value(&self) -> Value {
        // serde_json handles the camelCase conversion via #[serde(rename_all)]
        serde_json::to_value(self).expect("ResourceContent should always serialize")
    }

    fn annotations(&self) -> Option<&Annotations> {
        None
    }
}

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

    #[test]
    fn test_text_resource() {
        let content = ResourceContent::text("file:///test.txt", "Hello");

        assert_eq!(content.uri, "file:///test.txt");
        assert_eq!(content.mime_type, Some("text/plain".to_string()));
        assert_eq!(content.text, Some("Hello".to_string()));
        assert_eq!(content.blob, None);
    }

    #[test]
    fn test_text_resource_with_mime_type() {
        let content =
            ResourceContent::text("file:///data.json", "{}").with_mime_type("application/json");

        assert_eq!(content.mime_type, Some("application/json".to_string()));
    }

    #[test]
    fn test_blob_resource() {
        let content = ResourceContent::blob("file:///img.png", "base64data", "image/png");

        assert_eq!(content.uri, "file:///img.png");
        assert_eq!(content.mime_type, Some("image/png".to_string()));
        assert_eq!(content.text, None);
        assert_eq!(content.blob, Some("base64data".to_string()));
    }

    #[test]
    fn test_serialization_camel_case() {
        let content = ResourceContent::text("file:///test", "data").with_mime_type("text/plain");

        let value = content.to_value();
        let obj = value.as_object().unwrap();

        // Should use camelCase for mimeType
        assert!(obj.contains_key("uri"));
        assert!(obj.contains_key("mimeType"));
        assert!(obj.contains_key("text"));
        assert!(!obj.contains_key("mime_type")); // snake_case should NOT be present
    }

    #[test]
    fn test_content_type() {
        let content = ResourceContent::text("uri", "text");
        assert_eq!(content.content_type(), "resource");
    }
}
