//! Selector parser implementation using Pest
//!
//! This module contains the parsing logic for converting selector strings
//! into AST structures using the Pest parser generator.

use pest::iterators::Pair;
use pest::Parser;
use pest_derive::Parser;

use super::ast::{Combinator, SelectorPart, SimpleSelector, SimpleSelectorGroup};

// -----------------------------------------------------------------------------
// Parser Definition
// -----------------------------------------------------------------------------

#[derive(Parser)]
#[grammar = "parsers/selectors/selectors.pest"]
pub struct SelectorParser;

// -----------------------------------------------------------------------------
// Public API
// -----------------------------------------------------------------------------

/// Parse a selector string into a SimpleSelectorGroup
///
/// # Examples
/// ```
/// use wasot_compiler::parsers::selectors::parser::parse_selector;
///
/// let selector = parse_selector("div.container > p").unwrap();
/// ```
pub fn parse_selector(input: &str) -> Result<SimpleSelectorGroup, String> {
    let pairs =
        SelectorParser::parse(Rule::selector, input).map_err(|e| format!("Parse error: {e}"))?;

    // Get the first (and only) selector rule
    let selector_pair = pairs
        .into_iter()
        .next()
        .ok_or_else(|| "No selector found".to_string())?;

    // Find the selector_group inside
    let selector_group_pair = selector_pair
        .into_inner()
        .find(|p| p.as_rule() == Rule::selector_group)
        .ok_or_else(|| "No selector group found".to_string())?;

    parse_selector_group(selector_group_pair)
}

// -----------------------------------------------------------------------------
// Internal Parsing Functions
// -----------------------------------------------------------------------------

fn parse_selector_group(pair: Pair<Rule>) -> Result<SimpleSelectorGroup, String> {
    debug_assert_eq!(pair.as_rule(), Rule::selector_group);

    // For SimpleSelectorGroup, we only support single compound selectors (no comma separation)
    // If there are multiple selectors separated by commas, we'll just take the first one
    let compound_selector_pair = pair
        .into_inner()
        .find(|p| p.as_rule() == Rule::compound_selector)
        .ok_or_else(|| "No compound selector found".to_string())?;

    let selectors = parse_compound_selector(compound_selector_pair)?;
    Ok(SimpleSelectorGroup { selectors })
}

fn parse_compound_selector(pair: Pair<Rule>) -> Result<Vec<SelectorPart>, String> {
    debug_assert_eq!(pair.as_rule(), Rule::compound_selector);

    let mut selectors = Vec::new();
    let pairs = pair.into_inner().peekable();

    for pair in pairs {
        match pair.as_rule() {
            Rule::simple_selector => {
                let simple = parse_simple_selector(pair)?;
                selectors.push(SelectorPart::Simple(Box::new(simple)));
            }
            Rule::combinator => {
                let combinator = parse_combinator(pair)?;
                selectors.push(SelectorPart::Combinator(combinator));
            }
            _ => {}
        }
    }

    Ok(selectors)
}

fn parse_simple_selector(pair: Pair<Rule>) -> Result<SimpleSelector, String> {
    debug_assert_eq!(pair.as_rule(), Rule::simple_selector);

    let mut builder = SimpleSelector::builder();

    for inner_pair in pair.into_inner() {
        match inner_pair.as_rule() {
            Rule::universal_selector => {
                // Universal selector (*) - we'll handle this by not setting a tag
                // In a more complete implementation, we'd set tag to TagSelector::Universal
            }
            Rule::type_selector => {
                let type_name = parse_identifier(inner_pair.into_inner().next().unwrap())?;
                builder = builder.tag(&type_name);
            }
            Rule::id_selector => {
                let id = parse_identifier(inner_pair.into_inner().next().unwrap())?;
                builder = builder.id(&id);
            }
            Rule::class_selector => {
                let class = parse_identifier(inner_pair.into_inner().next().unwrap())?;
                builder = builder.class(&class);
            }
            Rule::attribute_selector => {
                builder = parse_attribute_selector(inner_pair, builder)?;
            }
            Rule::pseudo_class_selector => {
                builder = parse_pseudo_class_selector(inner_pair, builder)?;
            }
            _ => {}
        }
    }

    Ok(builder.build())
}

fn parse_attribute_selector(
    pair: Pair<Rule>,
    mut builder: SimpleSelectorBuilder,
) -> Result<SimpleSelectorBuilder, String> {
    debug_assert_eq!(pair.as_rule(), Rule::attribute_selector);

    let inner = pair
        .into_inner()
        .next()
        .ok_or_else(|| "Empty attribute selector".to_string())?;

    match inner.as_rule() {
        Rule::attribute_presence => {
            let attr_name = parse_identifier(inner.into_inner().next().unwrap())?;
            builder = builder.attribute(&attr_name);
        }
        Rule::attribute_exact_match => {
            let mut inner_pairs = inner.into_inner();
            let key = parse_identifier(inner_pairs.next().unwrap())?;
            // Handle optional value (empty attribute values)
            let value = if let Some(value_pair) = inner_pairs.next() {
                parse_identifier(value_pair)?
            } else {
                String::new() // Empty value for [attr=]
            };
            builder = builder.attribute_value(&key, &value);
        }
        Rule::attribute_negated_presence => {
            // For negated presence, we could extend the builder or use :not()
            // For now, we'll skip this
        }
        Rule::attribute_negated_match => {
            // For negated match, we could extend the builder or use :not()
            // For now, we'll skip this
        }
        Rule::attribute_starts_with | Rule::attribute_ends_with | Rule::attribute_contains => {
            // These would require extending the SimpleSelector structure
            // For now, we'll treat them as presence checks
            let mut inner_pairs = inner.into_inner();
            let key = parse_identifier(inner_pairs.next().unwrap())?;
            // Skip the optional value without panicking if it's missing
            let _value = inner_pairs.next().and_then(|p| parse_identifier(p).ok());
            builder = builder.attribute(&key);
        }
        _ => {}
    }

    Ok(builder)
}

fn parse_pseudo_class_selector(
    pair: Pair<Rule>,
    mut builder: SimpleSelectorBuilder,
) -> Result<SimpleSelectorBuilder, String> {
    debug_assert_eq!(pair.as_rule(), Rule::pseudo_class_selector);

    let inner = pair
        .into_inner()
        .next()
        .ok_or_else(|| "Empty pseudo-class selector".to_string())?;

    match inner.as_rule() {
        Rule::simple_pseudo => {
            let pseudo = inner.as_str();
            match pseudo {
                "first-child" => {
                    builder = builder.nth_child(1);
                }
                "last-child" => {
                    // Would need to extend SimpleSelector to support last-child
                    // For now, we'll skip this
                }
                _ => {}
            }
        }
        Rule::nth_functional_pseudo => {
            // The nth_functional_pseudo rule contains the function name as part of the whole match
            let text = inner.as_str();

            // Extract function name and argument
            if let Some(paren_idx) = text.find('(') {
                let func_name = &text[..paren_idx];

                // Find the argument_n rule which contains the actual number
                let n_str = inner
                    .into_inner()
                    .find(|p| p.as_rule() == Rule::argument_n)
                    .ok_or_else(|| "No argument_n in nth-pseudo".to_string())?
                    .as_str();

                let n = n_str
                    .parse::<usize>()
                    .map_err(|e| format!("Invalid nth value: {e}"))?;

                if func_name == "nth-child" {
                    builder = builder.nth_child(n);
                }
            }
        }
        Rule::not_pseudo => {
            // Parse the selector inside :not()
            let selector_group_pair = inner
                .into_inner()
                .find(|p| p.as_rule() == Rule::selector_group)
                .ok_or_else(|| "No selector group in :not()".to_string())?;

            // For simplicity, we'll only handle simple selectors in :not()
            let compound_selector_pair = selector_group_pair
                .into_inner()
                .find(|p| p.as_rule() == Rule::compound_selector)
                .ok_or_else(|| "No compound selector in :not()".to_string())?;

            let simple_selector_pair = compound_selector_pair
                .into_inner()
                .find(|p| p.as_rule() == Rule::simple_selector)
                .ok_or_else(|| "No simple selector in :not()".to_string())?;

            let not_selector = parse_simple_selector(simple_selector_pair)?;
            builder = builder.not(not_selector);
        }
        _ => {}
    }

    Ok(builder)
}

fn parse_combinator(pair: Pair<Rule>) -> Result<Combinator, String> {
    debug_assert_eq!(pair.as_rule(), Rule::combinator);

    let inner = pair
        .into_inner()
        .next()
        .ok_or_else(|| "Empty combinator".to_string())?;

    match inner.as_rule() {
        Rule::descendant => Ok(Combinator::Descendant),
        Rule::child => Ok(Combinator::Child),
        Rule::adjacent_sibling => Ok(Combinator::AdjacentSibling),
        Rule::general_sibling => Ok(Combinator::GeneralSibling),
        _ => Err(format!("Unknown combinator: {:?}", inner.as_rule())),
    }
}

fn parse_identifier(pair: Pair<Rule>) -> Result<String, String> {
    // Handle case where we might get whitespace instead of identifier
    if pair.as_rule() != Rule::identifier {
        return Err(format!("Expected identifier, got {:?}", pair.as_rule()));
    }

    let inner = pair
        .into_inner()
        .next()
        .ok_or_else(|| "Empty identifier".to_string())?;

    match inner.as_rule() {
        Rule::unquoted_identifier => Ok(inner.as_str().to_string()),
        Rule::quoted_string => {
            // Remove quotes and handle escapes
            let s = inner.as_str();
            let s = &s[1..s.len() - 1]; // Remove surrounding quotes
            let s = s.replace(r#"\""#, "\""); // Unescape quotes
            let s = s.replace(r"\\", r"\"); // Unescape backslashes
            Ok(s)
        }
        _ => Err(format!("Unknown identifier type: {:?}", inner.as_rule())),
    }
}

// Re-export SimpleSelectorBuilder for internal use
use super::ast::SimpleSelectorBuilder;

#[cfg(test)]
mod tests {
    use super::*;
    use crate::parsers::selectors::ast::TagSelector;

    #[test]
    fn test_parse_simple_type_selector() {
        let result = parse_selector("div").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.tag.is_some());
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_id_selector() {
        let result = parse_selector("#main").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.id, Some("main".to_string()));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_class_selector() {
        let result = parse_selector(".container").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.classes.contains("container"));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_compound_selector() {
        let result = parse_selector("div#main.container").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.tag.is_some());
            assert_eq!(selector.id, Some("main".to_string()));
            assert!(selector.classes.contains("container"));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_descendant_combinator() {
        let result = parse_selector("div p").unwrap();
        assert_eq!(result.selectors.len(), 3);

        assert!(matches!(result.selectors[0], SelectorPart::Simple(_)));
        assert_eq!(
            result.selectors[1],
            SelectorPart::Combinator(Combinator::Descendant)
        );
        assert!(matches!(result.selectors[2], SelectorPart::Simple(_)));
    }

    #[test]
    fn test_parse_child_combinator() {
        let result = parse_selector("div > p").unwrap();
        assert_eq!(result.selectors.len(), 3);

        assert!(matches!(result.selectors[0], SelectorPart::Simple(_)));
        assert_eq!(
            result.selectors[1],
            SelectorPart::Combinator(Combinator::Child)
        );
        assert!(matches!(result.selectors[2], SelectorPart::Simple(_)));
    }

    #[test]
    fn test_parse_attribute_presence() {
        let result = parse_selector("[disabled]").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector
                .attribute_presence
                .contains(&"disabled".to_string()));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_attribute_value() {
        let result = parse_selector("[role=navigation]").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(
                selector.attribute_values.get("role"),
                Some(&"navigation".to_string())
            );
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_quoted_identifier() {
        let result = parse_selector(r#"."class with spaces""#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.classes.contains("class with spaces"));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_nth_child() {
        let result = parse_selector(":nth-child(3)").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.nth_child, Some(3));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_not_pseudo_class() {
        let result = parse_selector("div:not(.disabled)").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.tag.is_some());
            assert_eq!(selector.not_selectors.len(), 1);
            assert!(selector.not_selectors[0].classes.contains("disabled"));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_complex_selector() {
        let result =
            parse_selector("section > div.container#main[role=main]:not(.hidden)").unwrap();
        assert_eq!(result.selectors.len(), 3);

        // First part: section
        assert!(matches!(result.selectors[0], SelectorPart::Simple(_)));

        // Combinator: >
        assert_eq!(
            result.selectors[1],
            SelectorPart::Combinator(Combinator::Child)
        );

        // Second part: div.container#main[role=main]:not(.hidden)
        if let SelectorPart::Simple(ref selector) = result.selectors[2] {
            assert!(selector.tag.is_some());
            assert_eq!(selector.id, Some("main".to_string()));
            assert!(selector.classes.contains("container"));
            assert_eq!(
                selector.attribute_values.get("role"),
                Some(&"main".to_string())
            );
            assert_eq!(selector.not_selectors.len(), 1);
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_multiple_classes() {
        let result = parse_selector(".red.bold.large").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.classes.contains("red"));
            assert!(selector.classes.contains("bold"));
            assert!(selector.classes.contains("large"));
            assert_eq!(selector.classes.len(), 3);
        } else {
            panic!("Expected Simple selector");
        }
    }

    // ==============================================================================
    // Edge Case Tests for Parser
    // ==============================================================================

    #[test]
    fn test_parse_empty_selector() {
        let result = parse_selector("");
        assert!(result.is_err(), "Empty selector should fail to parse");
    }

    #[test]
    fn test_parse_whitespace_only() {
        let result = parse_selector("   \t\n  ");
        assert!(result.is_err(), "Whitespace-only selector should fail");
    }

    #[test]
    fn test_parse_universal_selector() {
        let result = parse_selector("*").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            // The parser currently doesn't set tag for universal selector
            // This is a known limitation mentioned in the code
            assert!(selector.tag.is_none() || matches!(selector.tag, Some(TagSelector::Universal)));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_quoted_type_selector() {
        let result = parse_selector(r#""type with spaces""#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(
                selector.tag,
                Some(TagSelector::TypeName("type with spaces".to_string()))
            );
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_quoted_id_selector() {
        let result = parse_selector(r#"#"id with spaces""#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.id, Some("id with spaces".to_string()));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_escaped_quotes_in_identifier() {
        let result = parse_selector(r#"."class\"with\"quotes""#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.classes.contains(r#"class"with"quotes"#));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_attribute_quoted_value() {
        let result = parse_selector(r#"[title="Hello World"]"#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(
                selector.attribute_values.get("title"),
                Some(&"Hello World".to_string())
            );
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_multiple_attribute_selectors() {
        let result = parse_selector("[disabled][role=button][aria-label=Submit]").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector
                .attribute_presence
                .contains(&"disabled".to_string()));
            assert_eq!(
                selector.attribute_values.get("role"),
                Some(&"button".to_string())
            );
            assert_eq!(
                selector.attribute_values.get("aria-label"),
                Some(&"Submit".to_string())
            );
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_complex_compound_selector() {
        let result = parse_selector(
            "div#main.container.active[role=main][data-active=true]:nth-child(2):not(.hidden)",
        )
        .unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.tag.is_some());
            assert_eq!(selector.id, Some("main".to_string()));
            assert!(selector.classes.contains("container"));
            assert!(selector.classes.contains("active"));
            assert_eq!(
                selector.attribute_values.get("role"),
                Some(&"main".to_string())
            );
            assert_eq!(
                selector.attribute_values.get("data-active"),
                Some(&"true".to_string())
            );
            assert_eq!(selector.nth_child, Some(2));
            assert_eq!(selector.not_selectors.len(), 1);
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_nth_child_edge_cases() {
        // Test nth-child(0) - technically invalid in CSS but let's see how we handle it
        let result = parse_selector(":nth-child(0)").unwrap();
        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.nth_child, Some(0));
        }

        // Test nth-child(1)
        let result = parse_selector(":nth-child(1)").unwrap();
        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.nth_child, Some(1));
        }

        // Test large nth-child value
        let result = parse_selector(":nth-child(9999)").unwrap();
        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.nth_child, Some(9999));
        }
    }

    #[test]
    fn test_parse_first_child_pseudo() {
        let result = parse_selector(":first-child").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            // first-child is converted to nth-child(1)
            assert_eq!(selector.nth_child, Some(1));
        } else {
            panic!("Expected Simple selector");
        }
    }

    #[test]
    fn test_parse_nested_not_selector() {
        let _result = parse_selector("div:not(.modal:not(.active))");
        // This might fail as nested :not() is complex
        // Let's at least test single-level :not()
        let result = parse_selector("div:not(.modal)").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.not_selectors.len(), 1);
            assert!(selector.not_selectors[0].classes.contains("modal"));
        }
    }

    #[test]
    fn test_parse_multiple_combinators() {
        // Test chain with multiple combinators
        let result = parse_selector("body > main > section paragraph").unwrap();
        assert_eq!(result.selectors.len(), 7); // body, >, main, >, section, space, paragraph

        // Verify combinator types
        assert!(matches!(
            result.selectors[1],
            SelectorPart::Combinator(Combinator::Child)
        ));
        assert!(matches!(
            result.selectors[3],
            SelectorPart::Combinator(Combinator::Child)
        ));
        assert!(matches!(
            result.selectors[5],
            SelectorPart::Combinator(Combinator::Descendant)
        ));
    }

    #[test]
    fn test_parse_adjacent_sibling_combinator() {
        let result = parse_selector("h1 + p").unwrap();
        assert_eq!(result.selectors.len(), 3);

        assert!(matches!(result.selectors[0], SelectorPart::Simple(_)));
        assert_eq!(
            result.selectors[1],
            SelectorPart::Combinator(Combinator::AdjacentSibling)
        );
        assert!(matches!(result.selectors[2], SelectorPart::Simple(_)));
    }

    #[test]
    fn test_parse_general_sibling_combinator() {
        let result = parse_selector("h1 ~ p").unwrap();
        assert_eq!(result.selectors.len(), 3);

        assert!(matches!(result.selectors[0], SelectorPart::Simple(_)));
        assert_eq!(
            result.selectors[1],
            SelectorPart::Combinator(Combinator::GeneralSibling)
        );
        assert!(matches!(result.selectors[2], SelectorPart::Simple(_)));
    }

    #[test]
    fn test_parse_whitespace_around_combinators() {
        // Test various whitespace combinations
        let selectors = vec![
            "div>p",     // No whitespace
            "div > p",   // Normal whitespace
            "div  >  p", // Extra whitespace
            "div\t>\tp", // Tabs
            "div\n>\np", // Newlines
        ];

        for selector_str in selectors {
            let result = parse_selector(selector_str).unwrap();
            assert_eq!(result.selectors.len(), 3);
            assert_eq!(
                result.selectors[1],
                SelectorPart::Combinator(Combinator::Child)
            );
        }
    }

    #[test]
    fn test_parse_invalid_selectors() {
        // Test various invalid selectors
        let invalid_selectors = vec![
            ">",              // Starts with combinator
            "div >",          // Ends with combinator
            "div > > p",      // Double combinator
            "[]",             // Empty attribute selector
            "[:nth-child()]", // Empty nth-child
            "#",              // Empty ID
            ".",              // Empty class
            "div:not()",      // Empty :not()
        ];

        for selector_str in invalid_selectors {
            let result = parse_selector(selector_str);
            assert!(
                result.is_err(),
                "Selector '{selector_str}' should fail to parse"
            );
        }
    }

    #[test]
    fn test_parse_long_selector_chain() {
        // Test a very long selector chain
        let long_selector = "html body main section article div p span em strong";
        let result = parse_selector(long_selector).unwrap();

        // Count simple selectors (should be 10)
        let simple_count = result
            .selectors
            .iter()
            .filter(|s| matches!(s, SelectorPart::Simple(_)))
            .count();
        assert_eq!(simple_count, 10);

        // Count descendant combinators (should be 9)
        let combinator_count = result
            .selectors
            .iter()
            .filter(|s| matches!(s, SelectorPart::Combinator(Combinator::Descendant)))
            .count();
        assert_eq!(combinator_count, 9);
    }

    #[test]
    fn test_parse_mixed_quotes() {
        // Test mixing quoted and unquoted identifiers
        // Test mixing quoted and unquoted identifiers - split into separate tests to avoid raw string issues

        // Test quoted class
        let result = parse_selector(r#"div."quoted class""#).unwrap();
        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert!(selector.classes.contains("quoted class"));
        }

        // Test unquoted id
        let result = parse_selector("#unquoted-id").unwrap();
        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.id, Some("unquoted-id".to_string()));
        }

        // Test quoted attribute
        let result = parse_selector(r#"["quoted-attr"="quoted value"]"#).unwrap();
        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(
                selector.attribute_values.get("quoted-attr"),
                Some(&"quoted value".to_string())
            );
        }
    }

    #[test]
    fn test_parse_special_characters_in_identifiers() {
        // Test identifiers with dashes and underscores
        let result = parse_selector("custom-element._private-class#id_with_underscore").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(
                selector.tag,
                Some(TagSelector::TypeName("custom-element".to_string()))
            );
            assert!(selector.classes.contains("_private-class"));
            assert_eq!(selector.id, Some("id_with_underscore".to_string()));
        }
    }

    #[test]
    fn test_parse_attribute_starts_with() {
        // Note: The parser recognizes these but treats them as presence checks currently
        let result = parse_selector(r#"[href^="https"]"#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            // Currently treated as presence check
            assert!(selector.attribute_presence.contains(&"href".to_string()));
        }
    }

    #[test]
    fn test_parse_attribute_ends_with() {
        let result = parse_selector(r#"[href$=".pdf"]"#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            // Currently treated as presence check
            assert!(selector.attribute_presence.contains(&"href".to_string()));
        }
    }

    #[test]
    fn test_parse_attribute_contains() {
        let result = parse_selector(r#"[title*="hello"]"#).unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            // Currently treated as presence check
            assert!(selector.attribute_presence.contains(&"title".to_string()));
        }
    }

    #[test]
    fn test_parse_not_with_compound_selector() {
        let result = parse_selector("div:not(#modal.active[disabled])").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            assert_eq!(selector.not_selectors.len(), 1);
            let not_sel = &selector.not_selectors[0];
            assert_eq!(not_sel.id, Some("modal".to_string()));
            assert!(not_sel.classes.contains("active"));
            assert!(not_sel.attribute_presence.contains(&"disabled".to_string()));
        }
    }

    // ==============================================================================
    // Additional Tests for Specific Coverage Lines
    // ==============================================================================

    #[test]
    fn test_parse_selector_no_pairs() {
        // Test lines 37, 40 - when pairs iterator is empty or lacks selector_group
        use pest::Parser;

        // Create an invalid parse that produces empty pairs
        let result = SelectorParser::parse(Rule::selector, "");
        match result {
            Err(_) => (), // Expected - empty selector should fail
            Ok(pairs) => {
                // If it somehow parses, ensure our error handling works
                let pairs: Vec<_> = pairs.collect();
                if pairs.is_empty() {
                    // This would trigger line 40 error path
                    assert!(parse_selector("").is_err());
                }
            }
        }
    }

    #[test]
    fn test_parse_identifier_error_cases() {
        // Test lines 273-274, 277, 280, 292 - identifier parsing errors
        // We can't easily create malformed pairs directly, but we can test
        // the error conditions through invalid selector strings that would
        // exercise these paths

        // Invalid identifier cases
        let invalid_selectors = vec![
            "[=]",   // Empty attribute name
            "[key=", // Unclosed attribute
            ":(",    // Empty pseudo function
        ];

        for selector in invalid_selectors {
            let result = parse_selector(selector);
            assert!(result.is_err(), "Should fail for selector: {selector}");
        }
    }

    #[test]
    fn test_parse_attribute_empty_value() {
        // Test lines 148-149, 151, 153 - attribute with empty value
        let result = parse_selector("[key=]").unwrap();
        assert_eq!(result.selectors.len(), 1);

        if let SelectorPart::Simple(ref selector) = result.selectors[0] {
            // Empty value should be handled
            assert_eq!(selector.attribute_values.get("key"), Some(&String::new()));
        }
    }

    #[test]
    fn test_parse_attribute_negated_cases() {
        // Test lines 155-162 - attribute negated presence and match
        // These are recognized by the parser but currently skipped in implementation

        // Test that these don't crash the parser even if not fully implemented
        let selectors = vec![
            "[!disabled]",  // negated presence (currently skipped)
            "[key~=value]", // negated match (currently skipped)
        ];

        for selector_str in selectors {
            // These might parse or might fail depending on pest grammar
            // The important thing is they don't panic
            let _result = parse_selector(selector_str);
        }
    }

    #[test]
    fn test_parse_attribute_advanced_matches() {
        // Test lines 166-171 - starts_with, ends_with, contains
        let selectors = vec![
            r#"[href^="https"]"#, // starts with
            r#"[href$=".pdf"]"#,  // ends with
            r#"[title*="test"]"#, // contains
        ];

        for selector_str in selectors {
            let result = parse_selector(selector_str);
            // These should parse successfully and be treated as presence checks
            assert!(result.is_ok(), "Should parse: {selector_str}");

            if let Ok(parsed) = result {
                if let SelectorPart::Simple(ref selector) = parsed.selectors[0] {
                    // Currently these are all treated as presence checks
                    // Extract the attribute name from the selector string
                    let attr_name = if selector_str.contains("href") {
                        "href"
                    } else {
                        "title"
                    };
                    assert!(selector.attribute_presence.contains(&attr_name.to_string()));
                }
            }
        }
    }

    #[test]
    fn test_parse_pseudo_class_error_cases() {
        // Test lines 184, 187 - empty pseudo class selectors
        let invalid_pseudo = vec![
            ":",            // Just colon
            ":not()",       // Empty not
            ":nth-child()", // Empty nth-child
        ];

        for selector in invalid_pseudo {
            let result = parse_selector(selector);
            assert!(result.is_err(), "Should fail for: {selector}");
        }
    }

    #[test]
    fn test_parse_pseudo_last_child() {
        // Test line 196 - last-child pseudo (currently skipped)
        let result = parse_selector(":last-child");
        // This might parse or fail, but shouldn't panic
        match result {
            Ok(parsed) => {
                // If it parses, verify structure
                assert_eq!(parsed.selectors.len(), 1);
            }
            Err(_) => {
                // It's ok if it fails - this pseudo isn't fully implemented
            }
        }
    }

    #[test]
    fn test_parse_nth_pseudo_invalid_number() {
        // Test line 220 - invalid nth value parsing
        let result = parse_selector(":nth-child(abc)");
        assert!(result.is_err(), "Should fail with invalid number");

        let result = parse_selector(":nth-child(99999999999999999999)");
        // This should also fail due to number parsing overflow
        assert!(result.is_err(), "Should fail with overflow");
    }

    #[test]
    fn test_parse_nth_pseudo_missing_argument() {
        // Test lines 212, 214-215 - missing argument_n in nth-pseudo
        // This tests the error path when argument_n is not found
        let result = parse_selector(":nth-child()");
        assert!(result.is_err(), "Should fail with missing argument");
    }

    #[test]
    fn test_parse_not_pseudo_missing_parts() {
        // Test lines 229, 231-232, 235, 237-238, 240, 242-243 - missing parts in :not()
        let invalid_not = vec![
            ":not()", // Empty not
        ];

        for selector in invalid_not {
            let result = parse_selector(selector);
            assert!(result.is_err(), "Should fail for: {selector}");
        }
    }

    #[test]
    fn test_parse_combinator_error_cases() {
        // Test line 260, 267 - empty combinator or unknown combinator
        // We can't easily create invalid Rule variants, but we can test
        // through parse failures

        let invalid_combinators = vec![
            "div ++ p", // Invalid combinator
            "div >> p", // Invalid combinator
            "div || p", // Invalid combinator
        ];

        for selector in invalid_combinators {
            let result = parse_selector(selector);
            // These should fail at the pest level
            assert!(result.is_err(), "Should fail for: {selector}");
        }
    }

    #[test]
    fn test_parse_quoted_string_escapes() {
        // Test lines 286-290 - quoted string escape handling
        let selectors = vec![
            r#"."test\"quote""#,     // Escaped quote
            r#"."test\\backslash""#, // Escaped backslash
            r#"."test\"and\\both""#, // Both escapes
        ];

        for selector_str in selectors {
            let result = parse_selector(selector_str);
            assert!(result.is_ok(), "Should parse: {selector_str}");
        }
    }

    #[test]
    fn test_parse_complex_whitespace_handling() {
        // Test various whitespace edge cases that might hit uncovered lines
        let whitespace_selectors = vec![
            "   div   p   ", // Leading/trailing whitespace
            "div\t\tp",      // Tab characters
            "div\n\np",      // Newlines
            "div\r\np",      // Windows line endings
            "div   >   p",   // Whitespace around child combinator
            "div\t>\tp",     // Tabs around combinator
        ];

        for selector_str in whitespace_selectors {
            let result = parse_selector(selector_str);
            assert!(
                result.is_ok(),
                "Should parse with whitespace: {selector_str}"
            );
        }
    }

    #[test]
    fn test_parse_unknown_simple_selector_rule() {
        // This test is to ensure we handle unknown rules gracefully in simple_selector parsing
        // Lines 112-113, 118-119, 121 would be hit if we had unknown rule types

        // Since we can't inject unknown rules directly, we test that valid
        // but uncommon combinations work
        let result = parse_selector("*#id.class[attr]:first-child");
        assert!(result.is_ok());

        if let Ok(parsed) = result {
            if let SelectorPart::Simple(ref selector) = parsed.selectors[0] {
                assert_eq!(selector.id, Some("id".to_string()));
                assert!(selector.classes.contains("class"));
                assert!(selector.attribute_presence.contains(&"attr".to_string()));
                assert_eq!(selector.nth_child, Some(1));
            }
        }
    }

    #[test]
    fn test_edge_case_selector_combinations() {
        // Test edge cases that might hit the remaining uncovered lines
        let edge_cases = vec![
            "*",            // Universal selector only
            "#id",          // ID only
            ".class",       // Class only
            "[attr]",       // Attribute only
            ":first-child", // Pseudo only
        ];

        for selector_str in edge_cases {
            let result = parse_selector(selector_str);
            assert!(result.is_ok(), "Should parse edge case: {selector_str}");
        }
    }
}
