//! Fluent content builders
//!
//! Provides ergonomic builder API for creating content with annotations

use super::annotations::Annotations;
use super::types::{AudioContent, ImageContent, ResourceLink, TextContent};

/// Builder for text content
#[derive(Debug, Clone)]
pub struct TextContentBuilder {
    text: String,
    annotations: Option<Annotations>,
}

impl TextContentBuilder {
    /// Create new text content builder
    pub fn new(text: impl Into<String>) -> Self {
        Self {
            text: text.into(),
            annotations: None,
        }
    }

    /// Add audience annotation
    pub fn with_audience(mut self, audience: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .audience
            .get_or_insert_with(Vec::new)
            .push(audience.into());
        self
    }

    /// Set priority annotation (0.0 to 1.0)
    pub fn with_priority(mut self, priority: f64) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .priority = Some(priority.clamp(0.0, 1.0));
        self
    }

    /// Set last modified annotation
    pub fn with_last_modified(mut self, timestamp: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .last_modified = Some(timestamp.into());
        self
    }

    /// Set language annotation
    pub fn with_language(mut self, language: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .language = Some(language.into());
        self
    }

    /// Build text content
    pub fn build(self) -> TextContent {
        TextContent {
            r#type: "text".to_string(),
            text: self.text,
            annotations: self.annotations,
        }
    }
}

/// Builder for image content
#[derive(Debug, Clone)]
pub struct ImageContentBuilder {
    data: String,
    mime_type: String,
    annotations: Option<Annotations>,
}

impl ImageContentBuilder {
    /// Create new image content builder
    pub fn new(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
        Self {
            data: data.into(),
            mime_type: mime_type.into(),
            annotations: None,
        }
    }

    /// Add audience annotation
    pub fn with_audience(mut self, audience: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .audience
            .get_or_insert_with(Vec::new)
            .push(audience.into());
        self
    }

    /// Set priority annotation
    pub fn with_priority(mut self, priority: f64) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .priority = Some(priority.clamp(0.0, 1.0));
        self
    }

    /// Set last modified annotation
    pub fn with_last_modified(mut self, timestamp: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .last_modified = Some(timestamp.into());
        self
    }

    /// Set language annotation
    pub fn with_language(mut self, language: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .language = Some(language.into());
        self
    }

    /// Build image content
    pub fn build(self) -> ImageContent {
        ImageContent {
            r#type: "image".to_string(),
            data: self.data,
            mime_type: self.mime_type,
            annotations: self.annotations,
        }
    }
}

/// Builder for audio content
#[derive(Debug, Clone)]
pub struct AudioContentBuilder {
    data: String,
    mime_type: String,
    annotations: Option<Annotations>,
}

impl AudioContentBuilder {
    /// Create new audio content builder
    pub fn new(data: impl Into<String>, mime_type: impl Into<String>) -> Self {
        Self {
            data: data.into(),
            mime_type: mime_type.into(),
            annotations: None,
        }
    }

    /// Add audience annotation
    pub fn with_audience(mut self, audience: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .audience
            .get_or_insert_with(Vec::new)
            .push(audience.into());
        self
    }

    /// Set priority annotation
    pub fn with_priority(mut self, priority: f64) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .priority = Some(priority.clamp(0.0, 1.0));
        self
    }

    /// Set last modified annotation
    pub fn with_last_modified(mut self, timestamp: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .last_modified = Some(timestamp.into());
        self
    }

    /// Set language annotation
    pub fn with_language(mut self, language: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .language = Some(language.into());
        self
    }

    /// Build audio content
    pub fn build(self) -> AudioContent {
        AudioContent {
            r#type: "audio".to_string(),
            data: self.data,
            mime_type: self.mime_type,
            annotations: self.annotations,
        }
    }
}

/// Builder for resource links
#[derive(Debug, Clone)]
pub struct ResourceLinkBuilder {
    uri: String,
    title: Option<String>,
    annotations: Option<Annotations>,
}

impl ResourceLinkBuilder {
    /// Create new resource link builder
    pub fn new(uri: impl Into<String>) -> Self {
        Self {
            uri: uri.into(),
            title: None,
            annotations: None,
        }
    }

    /// Set title
    pub fn with_title(mut self, title: impl Into<String>) -> Self {
        self.title = Some(title.into());
        self
    }

    /// Add audience annotation
    pub fn with_audience(mut self, audience: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .audience
            .get_or_insert_with(Vec::new)
            .push(audience.into());
        self
    }

    /// Set priority annotation
    pub fn with_priority(mut self, priority: f64) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .priority = Some(priority.clamp(0.0, 1.0));
        self
    }

    /// Set last modified annotation
    pub fn with_last_modified(mut self, timestamp: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .last_modified = Some(timestamp.into());
        self
    }

    /// Set language annotation
    pub fn with_language(mut self, language: impl Into<String>) -> Self {
        self.annotations
            .get_or_insert_with(Annotations::new)
            .language = Some(language.into());
        self
    }

    /// Build resource link
    pub fn build(self) -> ResourceLink {
        ResourceLink {
            r#type: "resource".to_string(),
            uri: self.uri,
            title: self.title,
            annotations: self.annotations,
        }
    }
}

/// Convenience function to create text content builder
pub fn text(text: impl Into<String>) -> TextContentBuilder {
    TextContentBuilder::new(text)
}

/// Convenience function to create image content builder
pub fn image(data: impl Into<String>, mime_type: impl Into<String>) -> ImageContentBuilder {
    ImageContentBuilder::new(data, mime_type)
}

/// Convenience function to create audio content builder
pub fn audio(data: impl Into<String>, mime_type: impl Into<String>) -> AudioContentBuilder {
    AudioContentBuilder::new(data, mime_type)
}

/// Convenience function to create resource link builder
pub fn resource(uri: impl Into<String>) -> ResourceLinkBuilder {
    ResourceLinkBuilder::new(uri)
}

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

    #[test]
    fn test_text_builder() {
        let content = text("Hello, world!")
            .with_priority(0.9)
            .with_audience("user")
            .with_language("en")
            .build();

        assert_eq!(content.text, "Hello, world!");
        assert!(content.annotations.is_some());

        let ann = content.annotations.unwrap();
        assert_eq!(ann.priority, Some(0.9));
        assert_eq!(ann.audience, Some(vec!["user".to_string()]));
        assert_eq!(ann.language, Some("en".to_string()));
    }

    #[test]
    fn test_text_builder_multiple_audiences() {
        let content = text("Important message")
            .with_audience("user")
            .with_audience("admin")
            .build();

        let ann = content.annotations.unwrap();
        assert_eq!(
            ann.audience,
            Some(vec!["user".to_string(), "admin".to_string()])
        );
    }

    #[test]
    fn test_image_builder() {
        let content = image("base64data", "image/png")
            .with_priority(0.8)
            .with_last_modified("2025-01-01T00:00:00Z")
            .build();

        assert_eq!(content.data, "base64data");
        assert_eq!(content.mime_type, "image/png");

        let ann = content.annotations.unwrap();
        assert_eq!(ann.priority, Some(0.8));
        assert_eq!(ann.last_modified, Some("2025-01-01T00:00:00Z".to_string()));
    }

    #[test]
    fn test_audio_builder() {
        let content = audio("audiodata", "audio/wav")
            .with_priority(0.7)
            .with_language("en")
            .build();

        assert_eq!(content.data, "audiodata");
        assert_eq!(content.mime_type, "audio/wav");

        let ann = content.annotations.unwrap();
        assert_eq!(ann.priority, Some(0.7));
        assert_eq!(ann.language, Some("en".to_string()));
    }

    #[test]
    fn test_resource_builder() {
        let link = resource("file://test.txt")
            .with_title("Test File")
            .with_priority(0.9)
            .build();

        assert_eq!(link.uri, "file://test.txt");
        assert_eq!(link.title, Some("Test File".to_string()));

        let ann = link.annotations.unwrap();
        assert_eq!(ann.priority, Some(0.9));
    }

    #[test]
    fn test_builder_without_annotations() {
        let content = text("Plain text").build();

        assert_eq!(content.text, "Plain text");
        assert!(content.annotations.is_none());
    }

    #[test]
    fn test_priority_clamping() {
        let content1 = text("High").with_priority(1.5).build();
        let content2 = text("Low").with_priority(-0.5).build();

        assert_eq!(content1.annotations.unwrap().priority, Some(1.0));
        assert_eq!(content2.annotations.unwrap().priority, Some(0.0));
    }

    #[test]
    fn test_builder_type_usage() {
        // Test that builders can be constructed explicitly
        let builder = TextContentBuilder::new("test");
        let content = builder.with_priority(0.5).build();

        assert_eq!(content.text, "test");
        assert_eq!(content.annotations.unwrap().priority, Some(0.5));
    }
}
