//! Comprehensive tests for picture parsing functionality.
//!
//! These tests verify that picture elements are properly parsed through the entire
//! microformats pipeline, including integration with different property types
//! (u-photo, p-name, etc.) and various edge cases.

use microformats_parser::parse::Parser;
use microformats_types::{Document, Item, PropertyValue};
use url::Url;

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

    /// Helper function to parse HTML and return the first item
    fn parse_html_to_item(html: &str) -> Result<Item, microformats_parser::Error> {
        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        document
            .items
            .into_iter()
            .next()
            .ok_or_else(|| microformats_parser::Error::HtmlCodegen("No items found".to_string()))
    }

    /// Test u-photo property with simple picture element
    #[test]
    fn test_uphoto_simple_picture() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">My Blog Post</h1>
            <picture class="u-photo">
                <source srcset="/images/hero-800w.jpg 800w, /images/hero-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg" alt="Hero image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        // Verify the item structure
        assert_eq!(item.type_, vec!["h-entry"]);

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        // Should have one photo value
        assert_eq!(photo_property.len(), 1);

        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/fallback.jpg"
                );
                assert_eq!(image.alt, Some("Hero image".to_string()));
            }
            _ => panic!(
                "Expected Image property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }

    /// Test p-name property extraction from picture fallback img
    #[test]
    fn test_pname_from_picture() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Blog Post Title</h1>
            <picture class="p-name">
                <source srcset="/images/hero-800w.jpg 800w, /images/hero-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg" alt="Hero image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let name_property = item.properties.get("name").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No name property found".to_string())
        })?;

        assert_eq!(name_property.len(), 1);

        match &name_property[0] {
            PropertyValue::Plain(plain) => {
                assert_eq!(plain.to_string(), "Hero image");
            }
            _ => panic!(
                "Expected Plain property value for p-name, got: {:?}",
                name_property[0]
            ),
        }

        Ok(())
    }

    /// Test multiple picture elements with different properties
    #[test]
    fn test_multiple_pictures() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Blog Post with Images</h1>
            <picture class="u-photo">
                <source srcset="/images/hero-800w.jpg 800w, /images/hero-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/hero-fallback.jpg" alt="Hero image">
            </picture>
            <picture class="u-photo">
                <source srcset="/images/thumb-200w.jpg 200w" media="(min-width: 200px)" type="image/png">
                <img src="/images/thumb-fallback.png" alt="Thumbnail">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        // Should have two photo values
        assert_eq!(photo_property.len(), 2);

        // Verify both images
        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/hero-fallback.jpg"
                );
                assert_eq!(image.alt, Some("Hero image".to_string()));
            }
            _ => panic!(
                "Expected Image property value for first photo, got: {:?}",
                photo_property[0]
            ),
        }

        match &photo_property[1] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/thumb-fallback.png"
                );
                assert_eq!(image.alt, Some("Thumbnail".to_string()));
            }
            _ => panic!(
                "Expected Image property value for second photo, got: {:?}",
                photo_property[1]
            ),
        }

        Ok(())
    }

    /// Test picture with multiple source elements and different media queries
    #[test]
    fn test_picture_multiple_sources() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Responsive Image Post</h1>
            <picture class="u-photo">
                <source srcset="/images/desktop-1200w.jpg 1200w, /images/desktop-800w.jpg 800w"
                        media="(min-width: 1200px)" type="image/jpeg">
                <source srcset="/images/tablet-800w.jpg 800w, /images/tablet-400w.jpg 400w"
                        media="(min-width: 768px)" type="image/webp">
                <source srcset="/images/mobile-400w.jpg 400w"
                        media="(min-width: 320px)" type="image/png">
                <img src="/images/fallback.jpg" alt="Responsive hero image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        assert_eq!(photo_property.len(), 1);

        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/fallback.jpg"
                );
                assert_eq!(image.alt, Some("Responsive hero image".to_string()));
            }
            _ => panic!(
                "Expected Image property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }

    /// Test picture element with empty srcset (edge case)
    #[test]
    fn test_picture_empty_srcset() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Empty Source</h1>
            <picture class="u-photo">
                <source srcset="" media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg" alt="Fallback image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo");

        // Should still have the fallback image even with empty srcset
        assert!(photo_property.is_some());
        assert_eq!(photo_property.unwrap().len(), 1);

        Ok(())
    }

    /// Test picture without any source elements (only fallback img)
    #[test]
    fn test_picture_only_fallback() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Simple Image</h1>
            <picture class="u-photo">
                <img src="/images/simple.jpg" alt="Simple image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        assert_eq!(photo_property.len(), 1);

        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/simple.jpg"
                );
                assert_eq!(image.alt, Some("Simple image".to_string()));
            }
            _ => panic!(
                "Expected Image property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }

    /// Test picture element without alt text on fallback img
    #[test]
    fn test_picture_no_alt_text() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Image No Alt</h1>
            <picture class="u-photo">
                <source srcset="/images/hero-800w.jpg 800w, /images/hero-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        assert_eq!(photo_property.len(), 1);

        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/fallback.jpg"
                );
                assert_eq!(image.alt, None); // No alt text should be None
            }
            PropertyValue::Url(url_value) => {
                // If no alt text, it should return as URL instead of Image
                assert_eq!(
                    url_value.value().as_str(),
                    "https://example.com/images/fallback.jpg"
                );
            }
            _ => panic!(
                "Expected Image or Url property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }

    /// Test malformed picture HTML (missing closing tags, etc.)
    #[test]
    fn test_picture_malformed_html() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Malformed Picture</h1>
            <picture class="u-photo">
                <source srcset="/images/hero-800w.jpg 800w, /images/hero-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg" alt="Malformed image">
            <!-- Missing closing picture tag -->
        </article>
        "#;

        // Should still parse successfully despite malformed HTML
        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo");
        // Should still find the photo despite malformed HTML
        assert!(photo_property.is_some());

        Ok(())
    }

    /// Test picture with invalid/malformed srcset entries
    #[test]
    fn test_picture_malformed_srcset() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Bad Srcset</h1>
            <picture class="u-photo">
                <source srcset="/images/valid.jpg 400w, invalid-url, /images/valid2.jpg 800w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg" alt="Fallback">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        assert_eq!(photo_property.len(), 1);

        // Should still work with valid entries, ignoring malformed ones
        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/fallback.jpg"
                );
                assert_eq!(image.alt, Some("Fallback".to_string()));
            }
            _ => panic!(
                "Expected Image property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }

    /// Test picture element as part of h-card (avatar use case)
    #[test]
    fn test_picture_in_hcard() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <div class="h-card">
            <img class="u-photo" src="/avatar.jpg" alt="John Doe">
        </div>
        <article class="h-entry">
            <h1 class="p-name">Post by John</h1>
            <picture class="u-photo">
                <source srcset="/images/author-400w.jpg 400w, /images/author-200w.jpg 200w"
                        media="(min-width: 400px)" type="image/jpeg">
                <img src="/images/author-fallback.jpg" alt="John's photo">
            </picture>
        </article>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        // Should have 2 items: h-card and h-entry
        assert_eq!(document.items.len(), 2);

        // Check h-card (first item)
        let h_card = &document.items[0];
        assert_eq!(h_card.type_, vec!["h-card"]);

        let h_card_photo = h_card.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found in h-card".to_string())
        })?;
        assert_eq!(h_card_photo.len(), 1);

        // Check h-entry (second item)
        let h_entry = &document.items[1];
        assert_eq!(h_entry.type_, vec!["h-entry"]);

        let h_entry_photo = h_entry.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen(
                "No photo property found in h-entry".to_string(),
            )
        })?;
        assert_eq!(h_entry_photo.len(), 1);

        Ok(())
    }

    /// Test picture with video poster (if supported)
    #[test]
    fn test_video_with_poster() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Video</h1>
            <video class="u-photo" poster="/images/video-poster.jpg" width="800" height="600">
                <source src="/video.mp4" type="video/mp4">
            </video>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo");

        // Video elements with poster should be processed (future enhancement)
        // For now, this tests the current behavior
        assert!(photo_property.is_some()); // Should have at least something

        Ok(())
    }

    /// Test picture with relative URLs
    #[test]
    fn test_picture_relative_urls() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Relative URLs</h1>
            <picture class="u-photo">
                <source srcset="images/hero-800w.jpg 800w, images/hero-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="images/fallback.jpg" alt="Relative path image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        assert_eq!(photo_property.len(), 1);

        match &photo_property[0] {
            PropertyValue::Image(image) => {
                // Relative URLs should be resolved against base URL
                assert_eq!(
                    image.value.as_str(),
                    "https://example.com/images/fallback.jpg"
                );
                assert_eq!(image.alt, Some("Relative path image".to_string()));
            }
            _ => panic!(
                "Expected Image property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }

    /// Test picture with data URLs
    #[test]
    fn test_picture_data_urls() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Data URL</h1>
            <picture class="u-photo">
                <source srcset="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k= 1x"
                        type="image/jpeg">
                <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAX/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwCdABmX/9k= 2x"
                        alt="Data URL image">
            </picture>
        </article>
        "#;

        let item = parse_html_to_item(html)?;

        let photo_property = item.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;

        assert_eq!(photo_property.len(), 1);

        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert!(image.value.as_str().starts_with("data:image/jpeg;base64,"));
                assert_eq!(image.alt, Some("Data URL image".to_string()));
            }
            _ => panic!(
                "Expected Image property value, got: {:?}",
                photo_property[0]
            ),
        }

        Ok(())
    }
}

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

    /// Test picture parsing with feature flag disabled (if feature flags are implemented)
    #[test]
    fn test_picture_feature_flag_disabled() -> Result<(), microformats_parser::Error> {
        // This test would verify behavior when picture parsing feature is disabled
        // Implementation depends on how feature flags are structured in the project

        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post</h1>
            <picture class="u-photo">
                <img src="/image.jpg" alt="Image">
            </picture>
        </article>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;

        // When feature is disabled, picture elements might be ignored
        // or fall back to treating them as regular img elements
        let document = parser.into_document(Some(base_url))?;

        // At minimum should have the h-entry item
        assert_eq!(document.items.len(), 1);

        Ok(())
    }

    /// Test picture parsing with feature flag enabled
    #[test]
    fn test_picture_feature_flag_enabled() -> Result<(), microformats_parser::Error> {
        // This test verifies the enhanced picture parsing when feature is enabled

        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post</h1>
            <picture class="u-photo">
                <source srcset="/image-400w.jpg 400w, /image-800w.jpg 800w"
                        media="(min-width: 400px)" type="image/jpeg">
                <img src="/image-fallback.jpg" alt="Enhanced image">
            </picture>
        </article>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        assert_eq!(document.items.len(), 1);

        let item = &document.items[0];
        let photo_property = item.properties.get("photo");

        // With feature enabled, should have full picture parsing
        assert!(photo_property.is_some());

        Ok(())
    }
}

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

    /// Complete end-to-end test with realistic blog post HTML
    #[test]
    fn test_realistic_blog_post() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <!DOCTYPE html>
        <html>
        <head>
            <title>My Travel Blog</title>
        </head>
        <body>
            <article class="h-entry" id="travel-post-1">
                <h1 class="p-name">Amazing Trip to Japan</h1>
                <div class="p-author h-card">
                    <img class="u-photo" src="/images/author-avatar.jpg" alt="John Traveler">
                    <span class="p-name">John Traveler</span>
                </div>

                <picture class="u-photo">
                    <source srcset="/images/japan-hero-1200w.jpg 1200w, /images/japan-hero-800w.jpg 800w, /images/japan-hero-400w.jpg 400w"
                            media="(min-width: 1200px)" type="image/jpeg">
                    <source srcset="/images/japan-hero-tablet-800w.jpg 800w, /images/japan-hero-tablet-400w.jpg 400w"
                            media="(min-width: 768px)" type="image/webp">
                    <source srcset="/images/japan-hero-mobile-400w.jpg 400w, /images/japan-hero-mobile-200w.jpg 200w"
                            media="(min-width: 320px)" type="image/png">
                    <img src="/images/japan-hero-fallback.jpg" alt="Beautiful cherry blossoms in Tokyo">
                </picture>

                <div class="e-content">
                    <p>I recently visited Japan and it was absolutely amazing! The cherry blossoms were in full bloom.</p>

                    <picture class="u-photo">
                        <source srcset="/images/cherry-blossom-600w.jpg 600w"
                                media="(min-width: 600px)" type="image/jpeg">
                        <img src="/images/cherry-blossom-300w.jpg" alt="Close-up of cherry blossoms">
                    </picture>

                    <p>The temples were breathtaking and the food was incredible.</p>
                </div>
            </article>
        </body>
        </html>
        "#;

        let base_url = Url::parse("https://mytravelblog.example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        // Should have 2 items: h-entry and h-card
        assert_eq!(document.items.len(), 2);

        // Check h-entry
        let h_entry = &document.items[0];
        assert_eq!(h_entry.type_, vec!["h-entry"]);
        assert_eq!(h_entry.id, Some("travel-post-1".to_string()));

        // Verify properties
        let expected_properties = ["name", "author", "photo", "content"];
        for prop in &expected_properties {
            assert!(
                h_entry.properties.contains_key(prop),
                "Missing property: {}",
                prop
            );
        }

        // Check photo property (should have 2 images from the two picture elements)
        let photo_property = h_entry.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;
        assert_eq!(photo_property.len(), 2); // Two picture elements

        // Verify first image (hero image)
        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://mytravelblog.example.com/images/japan-hero-fallback.jpg"
                );
                assert_eq!(
                    image.alt,
                    Some("Beautiful cherry blossoms in Tokyo".to_string())
                );
            }
            _ => panic!("Expected Image property value for hero image"),
        }

        // Verify second image (cherry blossom close-up)
        match &photo_property[1] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://mytravelblog.example.com/images/cherry-blossom-300w.jpg"
                );
                assert_eq!(image.alt, Some("Close-up of cherry blossoms".to_string()));
            }
            _ => panic!("Expected Image property value for cherry blossom image"),
        }

        // Check h-card
        let h_card = &document.items[1];
        assert_eq!(h_card.type_, vec!["h-card"]);

        let h_card_photo = h_card.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found in h-card".to_string())
        })?;
        assert_eq!(h_card_photo.len(), 1);

        match &h_card_photo[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://mytravelblog.example.com/images/author-avatar.jpg"
                );
                assert_eq!(image.alt, Some("John Traveler".to_string()));
            }
            _ => panic!("Expected Image property value for author avatar"),
        }

        Ok(())
    }

    /// Test with various microformats patterns combined
    #[test]
    fn test_microformats_combination() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <div class="h-entry">
            <h2 class="p-name">Review: Great Restaurant</h2>

            <!-- Picture as main photo -->
            <picture class="u-photo">
                <source srcset="/restaurant-exterior-800w.jpg 800w, /restaurant-exterior-400w.jpg 400w"
                        media="(min-width: 600px)" type="image/jpeg">
                <img src="/restaurant-exterior-fallback.jpg" alt="Restaurant exterior">
            </picture>

            <!-- Regular img as secondary photo -->
            <img class="u-photo" src="/food-plate.jpg" alt="Delicious food">

            <!-- Picture with no alt text (edge case) -->
            <picture class="u-photo">
                <source srcset="/interior-600w.jpg 600w" type="image/png">
                <img src="/interior-fallback.png">
            </picture>

            <div class="e-content">
                <p>Great food and atmosphere! Highly recommended.</p>

                <!-- Nested h-review within content -->
                <div class="h-review">
                    <span class="p-rating">5</span> out of 5 stars
                    <p class="e-description">Amazing dining experience with excellent service.</p>
                </div>
            </div>
        </div>
        "#;

        let base_url = Url::parse("https://reviews.example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        // Should have 2 items: h-entry and h-review
        assert_eq!(document.items.len(), 2);

        // Check h-entry
        let h_entry = &document.items[0];
        assert_eq!(h_entry.type_, vec!["h-entry"]);

        // Should have photo property with 3 images (2 with alt text, 1 without)
        let photo_property = h_entry.properties.get("photo").ok_or_else(|| {
            microformats_parser::Error::HtmlCodegen("No photo property found".to_string())
        })?;
        assert_eq!(photo_property.len(), 3);

        // Verify first picture (with alt)
        match &photo_property[0] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://reviews.example.com/restaurant-exterior-fallback.jpg"
                );
                assert_eq!(image.alt, Some("Restaurant exterior".to_string()));
            }
            _ => panic!("Expected Image property value for first picture"),
        }

        // Verify regular img (with alt)
        match &photo_property[1] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://reviews.example.com/food-plate.jpg"
                );
                assert_eq!(image.alt, Some("Delicious food".to_string()));
            }
            _ => panic!("Expected Image property value for regular img"),
        }

        // Verify third picture (no alt - should be URL or Image with None alt)
        match &photo_property[2] {
            PropertyValue::Image(image) => {
                assert_eq!(
                    image.value.as_str(),
                    "https://reviews.example.com/interior-fallback.png"
                );
                assert_eq!(image.alt, None);
            }
            PropertyValue::Url(url_value) => {
                assert_eq!(
                    url_value.value().as_str(),
                    "https://reviews.example.com/interior-fallback.png"
                );
            }
            _ => panic!("Expected Image or Url property value for third picture without alt"),
        }

        // Check h-review within content
        let h_review = &document.items[1];
        assert_eq!(h_review.type_, vec!["h-review"]);

        // h-review should have content (from e-description mapping)
        assert!(h_review.properties.contains_key("content"));

        Ok(())
    }
}

#[cfg(test)]
mod performance_tests {
    use super::*;
    use std::time::Instant;

    /// Test that picture parsing doesn't significantly impact performance
    #[test]
    fn test_picture_parsing_performance() -> Result<(), microformats_parser::Error> {
        // Generate HTML with many picture elements
        let mut html =
            String::from(r#"<article class="h-entry"><h1 class="p-name">Performance Test</h1>"#);

        // Add 100 picture elements
        for i in 0..100 {
            html.push_str(&format!(
                r#"
            <picture class="u-photo">
                <source srcset="/images/{}-800w.jpg 800w, /images/{}-400w.jpg 400w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/{}-fallback.jpg" alt="Image {}">
            </picture>
            "#,
                i, i, i, i
            ));
        }

        html.push_str("</article>");

        let start = Instant::now();

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html)?;
        let document = parser.into_document(Some(base_url))?;

        let duration = start.elapsed();

        // Should parse within reasonable time (adjust threshold as needed)
        assert!(
            duration.as_millis() < 5000,
            "Picture parsing took too long: {:?}",
            duration
        );

        // Verify all images were parsed
        assert_eq!(document.items.len(), 1);
        let item = &document.items[0];
        let photo_property = item.properties.get("photo").unwrap();
        assert_eq!(photo_property.len(), 100);

        println!("Parsed 100 picture elements in {:?}", duration);

        Ok(())
    }
}

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

    /// Test parsing with completely invalid HTML structure
    #[test]
    fn test_completely_invalid_html() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Broken Picture</h1>
            <picture class="u-photo">
                <source srcset="/images/broken-1.jpg 400w
                <img src="/images/fallback.jpg" alt="Broken image">
            </picture>
        </article
        "#;

        // Should either parse successfully with fallback or fail gracefully
        let result = Parser::from_html(html.to_string());

        match result {
            Ok(mut parser) => {
                let base_url = Url::parse("https://example.com/").unwrap();
                let document = parser.into_document(Some(base_url))?;

                // Should still create the h-entry item even with broken HTML
                assert_eq!(document.items.len(), 1);
            }
            Err(e) => {
                // If it fails, it should be a specific parsing error, not a panic
                println!("Parsing failed as expected with error: {:?}", e);
                // This is acceptable behavior for severely malformed HTML
            }
        }

        Ok(())
    }

    /// Test with empty document
    #[test]
    fn test_empty_document() -> Result<(), microformats_parser::Error> {
        let html = r#"<html><body></body></html>"#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        // Should return empty document without errors
        assert_eq!(document.items.len(), 0);

        Ok(())
    }

    /// Test with malformed URLs in srcset
    #[test]
    fn test_malformed_urls() -> Result<(), microformats_parser::Error> {
        let html = r#"
        <article class="h-entry">
            <h1 class="p-name">Post with Bad URLs</h1>
            <picture class="u-photo">
                <source srcset="not-a-url 400w, https://valid.com/image.jpg 800w, ftp://invalid.com/image.jpg 600w"
                        media="(min-width: 800px)" type="image/jpeg">
                <img src="/images/fallback.jpg" alt="Valid fallback">
            </picture>
        </article>
        "#;

        let base_url = Url::parse("https://example.com/").unwrap();
        let mut parser = Parser::from_html(html.to_string())?;
        let document = parser.into_document(Some(base_url))?;

        // Should still parse successfully, handling invalid URLs gracefully
        assert_eq!(document.items.len(), 1);
        let item = &document.items[0];
        assert!(item.properties.contains_key("photo"));

        Ok(())
    }
}
