//! Integration tests for CleanedDocument with picture elements.
//!
//! These tests verify that picture parsing works correctly with document cleaning,
//! ensuring that both experimental extensions can be used together seamlessly.

#[cfg(all(feature = "cleaner", feature = "picture"))]
mod tests {
    use microformats::extensions::CleanedDocument;
    use microformats_types::{Class, Document, Item, KnownClass, PropertyValue};
    use url::Url;

    /// Helper function to parse HTML and return a document
    fn parse_html_to_document(html: &str, base_url: &Url) -> Result<Document, microformats::Error> {
        microformats::from_html(html, base_url)
    }

    /// Create HTML with picture elements that have recognized classes
    fn create_valid_picture_html() -> String {
        r#"
        <article class="h-entry">
            <h1 class="p-name">Valid Picture Post</h1>
            <picture class="u-photo">
                <source srcset="/images/valid-800w.jpg 800w, /images/valid-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/valid-fallback.jpg" alt="Valid picture">
            </picture>
            <div class="p-author h-card">
                <picture class="u-photo">
                    <img src="/images/avatar.jpg" alt="Author avatar">
                </picture>
                <span class="p-name">Valid Author</span>
            </div>
        </article>
        "#
        .to_string()
    }

    /// Create HTML with picture elements that have unrecognized classes
    fn create_mixed_class_html() -> String {
        r#"
        <article class="h-entry">
            <h1 class="p-name">Mixed Class Post</h1>
            <picture class="u-photo">
                <source srcset="/images/valid-800w.jpg 800w, /images/valid-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/valid-fallback.jpg" alt="Valid picture">
            </picture>
            <div class="p-author h-card">
                <picture class="u-photo">
                    <img src="/images/avatar.jpg" alt="Author avatar">
                </picture>
                <span class="p-name">Valid Author</span>
            </div>
            <!-- Custom classes that should be filtered out -->
            <div class="h-custom-post">
                <picture class="u-custom-photo">
                    <img src="/images/custom.jpg" alt="Custom picture">
                </picture>
                <span class="p-custom-name">Custom Content</span>
            </div>
            <div class="h-another-custom">
                <picture class="u-photo">
                    <img src="/images/another-custom.jpg" alt="Another custom">
                </picture>
            </div>
        </article>
        "#
        .to_string()
    }

    /// Create HTML with nested structures containing picture elements
    fn create_nested_picture_html() -> String {
        r#"
        <div class="h-feed">
            <h1 class="p-name">Picture Feed</h1>
            <div class="h-entry">
                <h2 class="p-name">Feed Entry 1</h2>
                <picture class="u-photo">
                    <source srcset="/images/feed1-800w.jpg 800w" type="image/jpeg">
                    <img src="/images/feed1-fallback.jpg" alt="Feed entry 1">
                </picture>
            </div>
            <div class="h-entry">
                <h2 class="p-name">Feed Entry 2</h2>
                <picture class="u-photo">
                    <source srcset="/images/feed2-800w.jpg 800w" type="image/jpeg">
                    <img src="/images/feed2-fallback.jpg" alt="Feed entry 2">
                </picture>
                <!-- Nested custom class that should be filtered -->
                <div class="h-custom-child">
                    <picture class="u-photo">
                        <img src="/images/custom-child.jpg" alt="Custom child">
                    </picture>
                </div>
            </div>
        </div>
        "#
        .to_string()
    }

    #[test]
    fn test_cleaned_document_preserves_valid_picture_elements() -> Result<(), microformats::Error> {
        let base_url = Url::parse("https://example.com/").unwrap();
        let html = create_valid_picture_html();

        let original_doc = parse_html_to_document(&html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        // Should preserve all recognized items
        assert_eq!(cleaned_doc.items.len(), 2); // h-entry and h-card (author)

        // Check h-entry
        let h_entry = &cleaned_doc.items[0];
        assert!(matches!(
            &h_entry.r#type[0],
            Class::Known(KnownClass::Entry)
        ));

        // Should have photo property from picture element
        let photo_property = h_entry
            .properties
            .get("photo")
            .ok_or_else(|| microformats::Error::Types(Default::default()))?;
        assert_eq!(photo_property.len(), 1);

        // Check h-card
        let h_card = &cleaned_doc.items[1];
        assert!(matches!(&h_card.r#type[0], Class::Known(KnownClass::Card)));

        let author_photo = h_card
            .properties
            .get("photo")
            .ok_or_else(|| microformats::Error::Types(Default::default()))?;
        assert_eq!(author_photo.len(), 1);

        Ok(())
    }

    #[test]
    fn test_cleaned_document_filters_unrecognized_classes_with_pictures(
    ) -> Result<(), microformats::Error> {
        let base_url = Url::parse("https://example.com/").unwrap();
        let html = create_mixed_class_html();

        let original_doc = parse_html_to_document(&html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        // Should filter out custom classes but keep recognized ones
        assert_eq!(cleaned_doc.items.len(), 2); // h-entry and h-card only

        // Verify h-entry is preserved
        let h_entry = &cleaned_doc.items[0];
        assert!(matches!(
            &h_entry.r#type[0],
            Class::Known(KnownClass::Entry)
        ));

        // Should still have its picture-based photo property
        assert!(h_entry.properties.contains_key("photo"));

        // Verify h-card is preserved
        let h_card = &cleaned_doc.items[1];
        assert!(matches!(&h_card.r#type[0], Class::Known(KnownClass::Card)));

        // Check that custom classes were removed from original
        let unrecognized = original_doc.unrecognized_items();
        assert_eq!(unrecognized.len(), 2); // Two custom items

        Ok(())
    }

    #[test]
    fn test_cleaned_document_filters_nested_custom_with_pictures() -> Result<(), microformats::Error>
    {
        let base_url = Url::parse("https://example.com/").unwrap();
        let html = create_nested_picture_html();

        let original_doc = parse_html_to_document(&html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        // Should preserve h-feed and h-entry items
        assert_eq!(cleaned_doc.items.len(), 1); // h-feed

        let h_feed = &cleaned_doc.items[0];
        assert!(matches!(&h_feed.r#type[0], Class::Known(KnownClass::Feed)));

        // Should have children (h-entry items)
        assert_eq!(h_feed.children.len(), 2);

        // Both children should be h-entry
        for child in &h_feed.children {
            assert!(matches!(&child.r#type[0], Class::Known(KnownClass::Entry)));
            // Should have photo properties from picture elements
            assert!(child.properties.contains_key("photo"));
        }

        // But custom child should be filtered out
        let second_entry = &h_feed.children[1];
        assert!(second_entry.children.is_empty());

        Ok(())
    }

    #[test]
    fn test_cleaned_document_preserves_picture_properties() -> Result<(), microformats::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Picture Properties Test</h1>
            <picture class="u-photo">
                <source srcset="/images/multi-800w.jpg 800w, /images/multi-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/multi-fallback.jpg" alt="Multi-source picture">
            </picture>
            <picture class="u-logo">
                <source srcset="/logo-200w.png 200w" type="image/png">
                <img src="/logo-fallback.png" alt="Company logo">
            </picture>
            <picture class="p-name">
                <img src="/images/name-picture.jpg" alt="Picture as name">
            </picture>
        </article>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let original_doc = parse_html_to_document(html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        assert_eq!(cleaned_doc.items.len(), 1);
        let item = &cleaned_doc.items[0];

        // Should have all three properties from picture elements
        assert!(item.properties.contains_key("photo"));
        assert!(item.properties.contains_key("logo"));
        assert!(item.properties.contains_key("name"));

        // Check photo property
        let photos = item.properties.get("photo").unwrap();
        assert_eq!(photos.len(), 1);

        // Check logo property
        let logos = item.properties.get("logo").unwrap();
        assert_eq!(logos.len(), 1);

        // Check name property (should have two: one from h1, one from picture)
        let names = item.properties.get("name").unwrap();
        assert_eq!(names.len(), 2);

        Ok(())
    }

    #[test]
    fn test_cleaned_document_with_picture_edge_cases() -> Result<(), microformats::Error> {
        let html = r#"
        <div class="h-entry h-valid">
            <h1 class="p-name">Edge Cases</h1>
            
            <!-- Picture with no alt text -->
            <picture class="u-photo">
                <source srcset="/images/no-alt-800w.jpg 800w" type="image/jpeg">
                <img src="/images/no-alt.jpg">
            </picture>
            
            <!-- Picture with malformed srcset -->
            <picture class="u-photo">
                <source srcset="invalid-url 400w, /images/valid.jpg 800w" type="image/jpeg">
                <img src="/images/malformed-fallback.jpg" alt="Malformed srcset">
            </picture>
            
            <!-- Picture only with img -->
            <picture class="u-logo">
                <img src="/images/img-only.png" alt="Img only picture">
            </picture>
        </div>
        
        <div class="h-invalid">
            <picture class="u-photo">
                <img src="/images/invalid.jpg" alt="Should be filtered">
            </picture>
        </div>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let original_doc = parse_html_to_document(html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        // Should only keep the valid entry (h-valid is a known class if it were defined, but it's not)
        // Since h-valid is not recognized, this should filter it out
        assert_eq!(cleaned_doc.items.len(), 0);

        // Original document should have one unrecognized item
        let unrecognized = original_doc.unrecognized_items();
        assert_eq!(unrecognized.len(), 2); // h-entry with h-valid, and h-invalid

        Ok(())
    }

    #[test]
    fn test_cleaned_document_preserves_document_metadata() -> Result<(), microformats::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Metadata Test</h1>
            <picture class="u-photo">
                <img src="/images/metadata.jpg" alt="Test image">
            </picture>
        </article>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut original_doc = parse_html_to_document(html, &base_url)?;

        // Set some metadata
        original_doc.lang = Some("en".to_string());

        let cleaned_doc = original_doc.with_only_known_classes();

        // Should preserve metadata
        assert_eq!(cleaned_doc.lang, original_doc.lang);
        assert_eq!(cleaned_doc.url, original_doc.url);
        assert_eq!(cleaned_doc.rels, original_doc.rels);

        Ok(())
    }

    #[test]
    fn test_cleaned_document_with_pictures_in_properties() -> Result<(), microformats::Error> {
        let html = r#"
        <div class="h-entry">
            <h1 class="p-name">Property Pictures</h1>
            
            <!-- Author as nested h-card with picture -->
            <div class="p-author h-card">
                <picture class="u-photo">
                    <img src="/images/author.jpg" alt="Author photo">
                </picture>
                <span class="p-name">John Doe</span>
            </div>
            
            <!-- Venue as nested h-card with picture -->
            <div class="p-location h-card">
                <picture class="u-photo">
                    <img src="/images/venue.jpg" alt="Venue photo">
                </picture>
                <span class="p-name">Conference Hall</span>
            </div>
            
            <!-- Custom nested item that should be filtered -->
            <div class="p-custom h-unknown">
                <picture class="u-photo">
                    <img src="/images/custom.jpg" alt="Custom">
                </picture>
            </div>
        </div>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let original_doc = parse_html_to_document(html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        assert_eq!(cleaned_doc.items.len(), 1);
        let item = &cleaned_doc.items[0];

        // Should preserve author and location properties
        assert!(item.properties.contains_key("author"));
        assert!(item.properties.contains_key("location"));

        // Should filter out custom property
        assert!(!item.properties.contains_key("custom"));

        // Check nested h-card items are preserved
        if let Some(PropertyValue::Item(author_card)) =
            item.properties.get("author").unwrap().first()
        {
            assert!(matches!(
                &author_card.r#type[0],
                Class::Known(KnownClass::Card)
            ));
            assert!(author_card.properties.contains_key("photo"));
        } else {
            panic!("Author should be an Item property");
        }

        Ok(())
    }

    #[test]
    fn test_cleaned_document_comprehensive_real_world() -> Result<(), microformats::Error> {
        let html = r#"
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <link rel="me" href="https://social.example.com/user">
        </head>
        <body>
            <article class="h-entry" id="post-123">
                <header class="p-author h-card">
                    <picture class="u-photo">
                        <source srcset="/avatars/author-2x.jpg 2x, /avatars/author-1x.jpg 1x" type="image/jpeg">
                        <img src="/avatars/author.jpg" alt="Jane Smith">
                    </picture>
                    <span class="p-name">Jane Smith</span>
                </header>
                
                <h1 class="p-name">My Amazing Trip</h1>
                
                <picture class="u-photo">
                    <source srcset="/photos/trip-1200w.jpg 1200w, /photos/trip-800w.jpg 800w, /photos/trip-400w.jpg 400w"
                            media="(min-width: 1200px)" type="image/jpeg">
                    <source srcset="/photos/trip-tablet.webp" media="(min-width: 768px)" type="image/webp">
                    <source srcset="/photos/trip-mobile.jpg" media="(min-width: 320px)" type="image/jpeg">
                    <img src="/photos/trip-fallback.jpg" alt="Beautiful mountain scenery">
                </picture>
                
                <div class="e-content">
                    <p>Had an amazing time on my recent trip!</p>
                    
                    <div class="p-location h-card">
                        <picture class="u-photo">
                            <source srcset="/locations/mountain-800w.jpg 800w" type="image/jpeg">
                            <img src="/locations/mountain.jpg" alt="Mountain Resort">
                        </picture>
                        <span class="p-name">Mountain Resort</span>
                    </div>
                </div>
                
                <!-- This custom section should be filtered out -->
                <div class="h-custom-section">
                    <picture class="u-photo">
                        <img src="/custom/image.jpg" alt="Custom content">
                    </picture>
                    <span class="p-custom-title">Custom Title</span>
                </div>
            </article>
        </body>
        </html>
        "#;

        let base_url = Url::parse("https://travel.example.com/").unwrap();
        let original_doc = parse_html_to_document(html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        // Should preserve the main h-entry
        assert_eq!(cleaned_doc.items.len(), 1);
        let h_entry = &cleaned_doc.items[0];
        assert!(matches!(
            &h_entry.r#type[0],
            Class::Known(KnownClass::Entry)
        ));
        assert_eq!(h_entry.id, Some("post-123".to_string()));

        // Should preserve author as nested h-card
        assert!(h_entry.properties.contains_key("author"));
        if let Some(PropertyValue::Item(author_card)) =
            h_entry.properties.get("author").unwrap().first()
        {
            assert!(matches!(
                &author_card.r#type[0],
                Class::Known(KnownClass::Card)
            ));
            assert!(author_card.properties.contains_key("photo"));
            assert!(author_card.properties.contains_key("name"));
        }

        // Should preserve main photo
        let photos = h_entry.properties.get("photo").unwrap();
        assert_eq!(photos.len(), 1);

        // Should preserve content
        assert!(h_entry.properties.contains_key("content"));

        // Content should have location as nested h-card
        if let Some(PropertyValue::Item(content_item)) =
            h_entry.properties.get("content").unwrap().first()
        {
            if let Some(location_items) = content_item.properties.get("location") {
                if let Some(PropertyValue::Item(location_card)) = location_items.first() {
                    assert!(matches!(
                        &location_card.r#type[0],
                        Class::Known(KnownClass::Card)
                    ));
                    assert!(location_card.properties.contains_key("photo"));
                }
            }
        }

        // Should preserve metadata
        assert_eq!(cleaned_doc.lang, Some("en".to_string()));
        assert_eq!(cleaned_doc.url, Some(base_url));

        // Check that custom item was filtered out
        let unrecognized = original_doc.unrecognized_items();
        assert_eq!(unrecognized.len(), 1); // The h-custom-section

        Ok(())
    }

    #[test]
    fn test_unrecognized_items_with_pictures() -> Result<(), microformats::Error> {
        let html = r#"
        <div class="h-entry">
            <h1 class="p-name">Mixed Document</h1>
            <picture class="u-photo">
                <img src="/images/valid.jpg" alt="Valid picture">
            </picture>
        </div>
        
        <div class="h-custom-1">
            <picture class="u-photo">
                <img src="/images/custom1.jpg" alt="Custom 1">
            </picture>
        </div>
        
        <div class="h-custom-2 h-also-custom">
            <picture class="u-custom-photo">
                <img src="/images/custom2.jpg" alt="Custom 2">
            </picture>
            <span class="p-custom-name">Custom Name</span>
        </div>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let document = parse_html_to_document(html, &base_url)?;

        let unrecognized = document.unrecognized_items();

        // Should find both custom items
        assert_eq!(unrecognized.len(), 2);

        // Check first custom item
        let custom1 = &unrecognized[0];
        assert!(custom1.r#type.iter().any(|c| c == "h-custom-1"));
        assert!(custom1.properties.contains_key("photo"));

        // Check second custom item (has multiple custom classes)
        let custom2 = &unrecognized[1];
        assert!(custom2.r#type.iter().any(|c| c == "h-custom-2"));
        assert!(custom2.r#type.iter().any(|c| c == "h-also-custom"));

        Ok(())
    }

    #[test]
    fn test_cleaned_document_empty_with_only_custom() -> Result<(), microformats::Error> {
        let html = r#"
        <div class="h-totally-custom">
            <h1 class="p-custom-name">Custom Document</h1>
            <picture class="u-custom-photo">
                <source srcset="/custom-800w.jpg 800w" type="image/jpeg">
                <img src="/custom.jpg" alt="Custom picture">
            </picture>
        </div>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let original_doc = parse_html_to_document(html, &base_url)?;
        let cleaned_doc = original_doc.with_only_known_classes();

        // Should have no items after cleaning
        assert!(cleaned_doc.items.is_empty());

        // But original should have one unrecognized item
        let unrecognized = original_doc.unrecognized_items();
        assert_eq!(unrecognized.len(), 1);

        Ok(())
    }
}
