//! AST builder - transforms pest parse tree into typed AST.

use indexmap::IndexMap;
use pest::iterators::{Pair, Pairs};

use super::expression::*;
use super::pattern::*;
use super::statement::*;
use crate::error::ParseError;
use crate::parser::Rule;

/// Build an AST from pest parse pairs.
pub struct AstBuilder;

/// Helper function to find a child of a specific rule type
fn find_child<'a>(pair: Pair<'a, Rule>, rule: Rule) -> Option<Pair<'a, Rule>> {
    pair.into_inner().find(|p| p.as_rule() == rule)
}

/// Helper function to get expression from where_clause (skips WHERE keyword)
fn get_where_expression(pair: Pair<'_, Rule>) -> Option<Pair<'_, Rule>> {
    find_child(pair, Rule::expression)
}

/// Normalize a symbol by stripping backticks from escaped identifiers.
/// Converts `name` to name, and handles escaped backticks (`` becomes `).
fn normalize_symbol(s: &str) -> String {
    if s.starts_with('`') && s.ends_with('`') && s.len() >= 2 {
        // Escaped symbolic name: strip outer backticks and unescape internal ``
        s[1..s.len()-1].replace("``", "`")
    } else {
        s.to_string()
    }
}

impl AstBuilder {
    /// Build a statement from the script rule.
    pub fn build_script(pairs: Pairs<'_, Rule>) -> Result<Vec<Statement>, ParseError> {
        let mut statements = Vec::new();
        for pair in pairs {
            match pair.as_rule() {
                Rule::script => {
                    // Descend into script to find statements
                    for inner in pair.into_inner() {
                        match inner.as_rule() {
                            Rule::statement => {
                                statements.push(Self::build_statement(inner)?);
                            }
                            Rule::EOI => {}
                            _ => {}
                        }
                    }
                }
                Rule::statement => {
                    statements.push(Self::build_statement(pair)?);
                }
                Rule::EOI => {}
                _ => {}
            }
        }
        Ok(statements)
    }

    /// Build a statement.
    pub fn build_statement(pair: Pair<'_, Rule>) -> Result<Statement, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::query | Rule::regular_query | Rule::standalone_call => {
                Ok(Statement::Query(Self::build_query(inner)?))
            }
            Rule::schema_command => {
                Ok(Statement::SchemaCommand(Self::build_schema_command(inner)?))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "query or schema_command".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a query.
    pub fn build_query(pair: Pair<'_, Rule>) -> Result<Query, ParseError> {
        match pair.as_rule() {
            Rule::query => {
                let inner = pair.into_inner().next().unwrap();
                Self::build_query(inner)
            }
            Rule::regular_query => Self::build_regular_query(pair),
            Rule::standalone_call => {
                let procedure = Self::build_procedure_call(pair.into_inner().next().unwrap())?;
                let call_clause = Clause::Call(CallClause::new(procedure));
                Ok(Query::single(SingleQuery::new(vec![call_clause])))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "query".to_string(),
                found: format!("{:?}", pair.as_rule()),
            }),
        }
    }

    /// Build a regular query (potentially with UNION).
    fn build_regular_query(pair: Pair<'_, Rule>) -> Result<Query, ParseError> {
        let mut parts = Vec::new();
        let mut union_all = false;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::single_query => {
                    parts.push(Self::build_single_query(inner)?);
                }
                Rule::union_clause => {
                    let mut has_all = false;
                    for u in inner.into_inner() {
                        match u.as_rule() {
                            Rule::ALL => has_all = true,
                            Rule::single_query => {
                                parts.push(Self::build_single_query(u)?);
                            }
                            _ => {}
                        }
                    }
                    union_all = has_all;
                }
                _ => {}
            }
        }

        Ok(Query { parts, union_all })
    }

    /// Build a single query.
    fn build_single_query(pair: Pair<'_, Rule>) -> Result<SingleQuery, ParseError> {
        let mut clauses = Vec::new();
        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::clause {
                clauses.push(Self::build_clause(inner)?);
            }
        }
        Ok(SingleQuery::new(clauses))
    }

    /// Build a clause.
    fn build_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::match_clause => Self::build_match_clause(inner),
            Rule::create_clause => Self::build_create_clause(inner),
            Rule::merge_clause => Self::build_merge_clause(inner),
            Rule::delete_clause => Self::build_delete_clause(inner),
            Rule::set_clause => Ok(Clause::Set(Self::build_set_clause(inner)?)),
            Rule::remove_clause => Ok(Clause::Remove(Self::build_remove_clause(inner)?)),
            Rule::with_clause => Self::build_with_clause(inner),
            Rule::return_clause => Self::build_return_clause(inner),
            Rule::unwind_clause => Self::build_unwind_clause(inner),
            Rule::foreach_clause => Self::build_foreach_clause(inner),
            Rule::call_clause => Self::build_call_clause(inner),
            _ => Err(ParseError::UnexpectedRule {
                expected: "clause".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a MATCH clause.
    fn build_match_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut optional = false;
        let mut pattern = None;
        let mut where_clause = None;
        let mut hints = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::OPTIONAL => optional = true,
                Rule::pattern => pattern = Some(Self::build_pattern(inner)?),
                Rule::where_clause => {
                    if let Some(expr) = get_where_expression(inner) {
                        where_clause = Some(Self::build_expression(expr)?);
                    }
                }
                Rule::hint => {
                    hints.push(Self::build_hint(inner)?);
                }
                _ => {}
            }
        }

        let pattern = pattern.ok_or_else(|| ParseError::MissingElement("pattern".to_string()))?;
        let mut match_clause = MatchClause::new(pattern);
        match_clause.where_clause = where_clause;
        match_clause.hints = hints;

        if optional {
            Ok(Clause::OptionalMatch(match_clause))
        } else {
            Ok(Clause::Match(match_clause))
        }
    }

    /// Build a hint.
    fn build_hint(pair: Pair<'_, Rule>) -> Result<MatchHint, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::index_hint => {
                let mut parts = inner.into_inner();
                let var = parts.next().unwrap().as_str().to_string();
                let label = parts.next().unwrap().as_str().to_string();
                let prop = parts.next().unwrap().as_str().to_string();
                Ok(MatchHint::UseIndex(var, label, prop))
            }
            Rule::scan_hint => {
                let mut parts = inner.into_inner();
                let var = parts.next().unwrap().as_str().to_string();
                let label = parts.next().unwrap().as_str().to_string();
                Ok(MatchHint::UseScan(var, label))
            }
            Rule::join_hint => {
                let vars: Vec<String> =
                    inner.into_inner().map(|p| p.as_str().to_string()).collect();
                Ok(MatchHint::UseJoin(vars))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "hint".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a CREATE clause.
    fn build_create_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let pattern_pair = find_child(pair, Rule::pattern)
            .ok_or_else(|| ParseError::MissingElement("pattern".to_string()))?;
        let pattern = Self::build_pattern(pattern_pair)?;
        Ok(Clause::Create(CreateClause::new(pattern)))
    }

    /// Build a MERGE clause.
    fn build_merge_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut pattern_part = None;
        let mut on_create = None;
        let mut on_match = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::pattern_part => {
                    pattern_part = Some(Self::build_pattern_part(inner)?);
                }
                Rule::merge_action => {
                    let mut is_create = false;
                    let mut set_clause = None;
                    for action_inner in inner.into_inner() {
                        match action_inner.as_rule() {
                            Rule::CREATE => is_create = true,
                            Rule::MATCH => is_create = false,
                            Rule::set_clause => {
                                set_clause = Some(Self::build_set_clause(action_inner)?);
                            }
                            _ => {}
                        }
                    }
                    if is_create {
                        on_create = set_clause;
                    } else {
                        on_match = set_clause;
                    }
                }
                _ => {}
            }
        }

        let pattern_part =
            pattern_part.ok_or_else(|| ParseError::MissingElement("pattern".to_string()))?;
        let mut merge = MergeClause::new(pattern_part);
        merge.on_create = on_create;
        merge.on_match = on_match;

        Ok(Clause::Merge(merge))
    }

    /// Build a DELETE clause.
    fn build_delete_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut detach = false;
        let mut expressions = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::DETACH => detach = true,
                Rule::expression_list => {
                    for expr in inner.into_inner() {
                        expressions.push(Self::build_expression(expr)?);
                    }
                }
                _ => {}
            }
        }

        if detach {
            Ok(Clause::Delete(DeleteClause::detach(expressions)))
        } else {
            Ok(Clause::Delete(DeleteClause::new(expressions)))
        }
    }

    /// Build a SET clause.
    fn build_set_clause(pair: Pair<'_, Rule>) -> Result<SetClause, ParseError> {
        let mut items = Vec::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::set_item {
                items.push(Self::build_set_item(inner)?);
            }
        }

        Ok(SetClause::new(items))
    }

    /// Build a SET item.
    fn build_set_item(pair: Pair<'_, Rule>) -> Result<SetItem, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair.into_inner().collect();

        // Check what kind of SET item this is
        if parts.len() >= 2 {
            let first = &parts[0];
            match first.as_rule() {
                Rule::property_expr => {
                    // n.prop = value
                    let prop_expr = Self::build_expression(parts.remove(0))?;
                    let value = Self::build_expression(parts.remove(0))?;
                    if let Expression::PropertyAccess(base, prop) = prop_expr {
                        Ok(SetItem::Property(*base, prop, value))
                    } else {
                        Err(ParseError::UnexpectedRule {
                            expected: "property access".to_string(),
                            found: "expression".to_string(),
                        })
                    }
                }
                Rule::symbol => {
                    let var = parts.remove(0).as_str().to_string();
                    if !parts.is_empty() {
                        let second = &parts[0];
                        match second.as_rule() {
                            Rule::node_labels => {
                                // n:Label1:Label2
                                let labels = Self::build_node_labels(parts.remove(0))?;
                                Ok(SetItem::Labels(var, labels))
                            }
                            _ => {
                                // n = expr or n += expr
                                // For simplicity, treat as all properties
                                let expr = Self::build_expression(parts.remove(0))?;
                                Ok(SetItem::AllProperties(var, expr))
                            }
                        }
                    } else {
                        Err(ParseError::MissingElement("set value".to_string()))
                    }
                }
                _ => Err(ParseError::UnexpectedRule {
                    expected: "property or symbol".to_string(),
                    found: format!("{:?}", first.as_rule()),
                }),
            }
        } else {
            Err(ParseError::MissingElement("set item parts".to_string()))
        }
    }

    /// Build a REMOVE clause.
    fn build_remove_clause(pair: Pair<'_, Rule>) -> Result<RemoveClause, ParseError> {
        let mut items = Vec::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::remove_item {
                items.push(Self::build_remove_item(inner)?);
            }
        }

        Ok(RemoveClause::new(items))
    }

    /// Build a REMOVE item.
    fn build_remove_item(pair: Pair<'_, Rule>) -> Result<RemoveItem, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair.into_inner().collect();

        if parts.is_empty() {
            return Err(ParseError::MissingElement("remove item".to_string()));
        }

        let first = &parts[0];
        match first.as_rule() {
            Rule::property_expr => {
                let prop_expr = Self::build_expression(parts.remove(0))?;
                if let Expression::PropertyAccess(base, prop) = prop_expr {
                    Ok(RemoveItem::Property(*base, prop))
                } else {
                    Err(ParseError::UnexpectedRule {
                        expected: "property access".to_string(),
                        found: "expression".to_string(),
                    })
                }
            }
            Rule::symbol => {
                let var = parts.remove(0).as_str().to_string();
                if !parts.is_empty() && parts[0].as_rule() == Rule::node_labels {
                    let labels = Self::build_node_labels(parts.remove(0))?;
                    Ok(RemoveItem::Labels(var, labels))
                } else {
                    Err(ParseError::MissingElement("labels".to_string()))
                }
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "property or symbol".to_string(),
                found: format!("{:?}", first.as_rule()),
            }),
        }
    }

    /// Build a WITH clause.
    fn build_with_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut projection = None;
        let mut where_clause = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::projection_body => {
                    projection = Some(Self::build_projection(inner)?);
                }
                Rule::where_clause => {
                    if let Some(expr) = get_where_expression(inner) {
                        where_clause = Some(Self::build_expression(expr)?);
                    }
                }
                _ => {}
            }
        }

        let projection =
            projection.ok_or_else(|| ParseError::MissingElement("projection".to_string()))?;
        let mut with = WithClause::new(projection);
        with.where_clause = where_clause;

        Ok(Clause::With(with))
    }

    /// Build a RETURN clause.
    fn build_return_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let projection_pair = find_child(pair, Rule::projection_body)
            .ok_or_else(|| ParseError::MissingElement("projection_body".to_string()))?;
        let projection = Self::build_projection(projection_pair)?;
        Ok(Clause::Return(ReturnClause::new(projection)))
    }

    /// Build a projection.
    fn build_projection(pair: Pair<'_, Rule>) -> Result<Projection, ParseError> {
        let mut distinct = false;
        let mut items = ProjectionItems::All;
        let mut order_by = None;
        let mut skip = None;
        let mut limit = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::DISTINCT => distinct = true,
                Rule::projection_items => {
                    items = Self::build_projection_items(inner)?;
                }
                Rule::order_clause => {
                    order_by = Some(Self::build_order_clause(inner)?);
                }
                Rule::skip_clause => {
                    if let Some(expr) = find_child(inner, Rule::expression) {
                        skip = Some(Self::build_expression(expr)?);
                    }
                }
                Rule::limit_clause => {
                    if let Some(expr) = find_child(inner, Rule::expression) {
                        limit = Some(Self::build_expression(expr)?);
                    }
                }
                _ => {}
            }
        }

        Ok(Projection {
            distinct,
            items,
            order_by,
            skip,
            limit,
        })
    }

    /// Build projection items.
    fn build_projection_items(pair: Pair<'_, Rule>) -> Result<ProjectionItems, ParseError> {
        let mut items = Vec::new();
        let mut has_star = false;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::projection_item => {
                    items.push(Self::build_projection_item(inner)?);
                }
                _ => {
                    // Check for "*"
                    if inner.as_str() == "*" {
                        has_star = true;
                    }
                }
            }
        }

        if has_star && items.is_empty() {
            Ok(ProjectionItems::All)
        } else {
            Ok(ProjectionItems::Explicit(items))
        }
    }

    /// Build a projection item.
    fn build_projection_item(pair: Pair<'_, Rule>) -> Result<ProjectionItem, ParseError> {
        let mut expression = None;
        let mut alias = None;
        let mut original_text = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::expression => {
                    // Capture the original source text before parsing
                    original_text = Some(inner.as_str().trim().to_string());
                    expression = Some(Self::build_expression(inner)?);
                }
                Rule::symbol => {
                    // Normalize symbol to strip backticks from escaped identifiers
                    alias = Some(normalize_symbol(inner.as_str()));
                }
                _ => {}
            }
        }

        let expression =
            expression.ok_or_else(|| ParseError::MissingElement("expression".to_string()))?;
        Ok(ProjectionItem { expression, alias, original_text })
    }

    /// Build ORDER BY clause.
    fn build_order_clause(pair: Pair<'_, Rule>) -> Result<Vec<OrderItem>, ParseError> {
        let mut items = Vec::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::order_item {
                items.push(Self::build_order_item(inner)?);
            }
        }

        Ok(items)
    }

    /// Build an order item.
    fn build_order_item(pair: Pair<'_, Rule>) -> Result<OrderItem, ParseError> {
        let mut expression = None;
        let mut direction = OrderDirection::Ascending;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::expression => {
                    expression = Some(Self::build_expression(inner)?);
                }
                Rule::ASC => direction = OrderDirection::Ascending,
                Rule::DESC => direction = OrderDirection::Descending,
                _ => {}
            }
        }

        let expression =
            expression.ok_or_else(|| ParseError::MissingElement("expression".to_string()))?;
        Ok(OrderItem {
            expression,
            direction,
        })
    }

    /// Build an UNWIND clause.
    fn build_unwind_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut expression = None;
        let mut variable = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::expression => {
                    expression = Some(Self::build_expression(inner)?);
                }
                Rule::symbol => {
                    variable = Some(inner.as_str().to_string());
                }
                _ => {}
            }
        }

        let expression =
            expression.ok_or_else(|| ParseError::MissingElement("expression".to_string()))?;
        let variable =
            variable.ok_or_else(|| ParseError::MissingElement("variable".to_string()))?;

        Ok(Clause::Unwind(UnwindClause::new(expression, variable)))
    }

    /// Build a FOREACH clause.
    fn build_foreach_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut variable = None;
        let mut expression = None;
        let mut clauses = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::symbol => {
                    if variable.is_none() {
                        variable = Some(inner.as_str().to_string());
                    }
                }
                Rule::expression => {
                    expression = Some(Self::build_expression(inner)?);
                }
                Rule::update_clause => {
                    clauses.push(Self::build_update_clause(inner)?);
                }
                _ => {}
            }
        }

        let variable =
            variable.ok_or_else(|| ParseError::MissingElement("variable".to_string()))?;
        let expression =
            expression.ok_or_else(|| ParseError::MissingElement("expression".to_string()))?;

        Ok(Clause::Foreach(ForeachClause::new(
            variable, expression, clauses,
        )))
    }

    /// Build an update clause (for FOREACH).
    fn build_update_clause(pair: Pair<'_, Rule>) -> Result<UpdateClause, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::create_clause => {
                if let Clause::Create(c) = Self::build_create_clause(inner)? {
                    Ok(UpdateClause::Create(c))
                } else {
                    unreachable!()
                }
            }
            Rule::merge_clause => {
                if let Clause::Merge(m) = Self::build_merge_clause(inner)? {
                    Ok(UpdateClause::Merge(m))
                } else {
                    unreachable!()
                }
            }
            Rule::set_clause => Ok(UpdateClause::Set(Self::build_set_clause(inner)?)),
            Rule::delete_clause => {
                if let Clause::Delete(d) = Self::build_delete_clause(inner)? {
                    Ok(UpdateClause::Delete(d))
                } else {
                    unreachable!()
                }
            }
            Rule::remove_clause => Ok(UpdateClause::Remove(Self::build_remove_clause(inner)?)),
            Rule::foreach_clause => {
                if let Clause::Foreach(f) = Self::build_foreach_clause(inner)? {
                    Ok(UpdateClause::Foreach(f))
                } else {
                    unreachable!()
                }
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "update clause".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a CALL clause.
    fn build_call_clause(pair: Pair<'_, Rule>) -> Result<Clause, ParseError> {
        let mut procedure = None;
        let mut yield_clause = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::procedure_call => {
                    procedure = Some(Self::build_procedure_call(inner)?);
                }
                Rule::yield_clause => {
                    yield_clause = Some(Self::build_yield_clause(inner)?);
                }
                _ => {}
            }
        }

        let procedure =
            procedure.ok_or_else(|| ParseError::MissingElement("procedure".to_string()))?;
        let mut call = CallClause::new(procedure);
        call.yield_items = yield_clause;

        Ok(Clause::Call(call))
    }

    /// Build a procedure call.
    fn build_procedure_call(pair: Pair<'_, Rule>) -> Result<ProcedureCall, ParseError> {
        let mut namespace = Vec::new();
        let mut name = String::new();
        let mut arguments = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::procedure_name => {
                    for name_part in inner.into_inner() {
                        match name_part.as_rule() {
                            Rule::namespace => {
                                for ns in name_part.into_inner() {
                                    namespace.push(ns.as_str().to_string());
                                }
                            }
                            Rule::symbol => {
                                name = name_part.as_str().to_string();
                            }
                            _ => {}
                        }
                    }
                }
                Rule::expression => {
                    arguments.push(Self::build_expression(inner)?);
                }
                _ => {}
            }
        }

        Ok(ProcedureCall::with_namespace(namespace, name, arguments))
    }

    /// Build a YIELD clause.
    fn build_yield_clause(pair: Pair<'_, Rule>) -> Result<YieldClause, ParseError> {
        let mut items = YieldItems::All;
        let mut where_clause = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::yield_items => {
                    items = Self::build_yield_items(inner)?;
                }
                Rule::where_clause => {
                    if let Some(expr) = get_where_expression(inner) {
                        where_clause = Some(Self::build_expression(expr)?);
                    }
                }
                _ => {}
            }
        }

        Ok(YieldClause {
            items,
            where_clause,
        })
    }

    /// Build yield items.
    fn build_yield_items(pair: Pair<'_, Rule>) -> Result<YieldItems, ParseError> {
        let mut items = Vec::new();
        let pair_str = pair.as_str().trim();

        // Check if the entire pair is just "*"
        if pair_str == "*" {
            return Ok(YieldItems::All);
        }

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::yield_item => {
                    items.push(Self::build_yield_item(inner)?);
                }
                _ => {
                    if inner.as_str() == "*" {
                        return Ok(YieldItems::All);
                    }
                }
            }
        }

        Ok(YieldItems::Explicit(items))
    }

    /// Build a yield item.
    fn build_yield_item(pair: Pair<'_, Rule>) -> Result<YieldItem, ParseError> {
        let mut name = String::new();
        let mut alias = None;

        for part in pair.into_inner() {
            if part.as_rule() == Rule::symbol {
                if name.is_empty() {
                    // First symbol is the name
                    name = normalize_symbol(part.as_str());
                } else {
                    // Second symbol (after AS) is the alias
                    alias = Some(normalize_symbol(part.as_str()));
                }
            }
            // else: Skip AS keyword and other tokens
        }

        Ok(YieldItem { name, alias })
    }

    /// Build a pattern.
    pub fn build_pattern(pair: Pair<'_, Rule>) -> Result<Pattern, ParseError> {
        let mut parts = Vec::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::pattern_part {
                parts.push(Self::build_pattern_part(inner)?);
            }
        }

        Ok(Pattern::new(parts))
    }

    /// Build a pattern part.
    fn build_pattern_part(pair: Pair<'_, Rule>) -> Result<PatternPart, ParseError> {
        let mut variable = None;
        let mut element = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::symbol => {
                    variable = Some(inner.as_str().to_string());
                }
                Rule::anonymous_pattern_part => {
                    element = Some(Self::build_anonymous_pattern_part(inner)?);
                }
                _ => {}
            }
        }

        let element =
            element.ok_or_else(|| ParseError::MissingElement("pattern element".to_string()))?;

        Ok(PatternPart { variable, element })
    }

    /// Build an anonymous pattern part.
    fn build_anonymous_pattern_part(pair: Pair<'_, Rule>) -> Result<PatternElement, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::shortest_path_pattern => {
                let element = Self::build_pattern_element(inner.into_inner().next().unwrap())?;
                Ok(PatternElement::ShortestPath(Box::new(element)))
            }
            Rule::all_shortest_paths_pattern => {
                let element = Self::build_pattern_element(inner.into_inner().next().unwrap())?;
                Ok(PatternElement::AllShortestPaths(Box::new(element)))
            }
            Rule::pattern_element => Self::build_pattern_element(inner),
            _ => Err(ParseError::UnexpectedRule {
                expected: "pattern element".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a pattern element.
    fn build_pattern_element(pair: Pair<'_, Rule>) -> Result<PatternElement, ParseError> {
        let mut start = None;
        let mut chain = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::node_pattern => {
                    if start.is_none() {
                        start = Some(Self::build_node_pattern(inner)?);
                    }
                }
                Rule::pattern_element_chain => {
                    let (rel, node) = Self::build_pattern_element_chain(inner)?;
                    chain.push((rel, node));
                }
                Rule::pattern_element => {
                    // Parenthesized pattern
                    return Self::build_pattern_element(inner);
                }
                _ => {}
            }
        }

        let start = start.ok_or_else(|| ParseError::MissingElement("start node".to_string()))?;
        Ok(PatternElement::Chain(PatternChain::with_chain(
            start, chain,
        )))
    }

    /// Build a pattern element chain.
    fn build_pattern_element_chain(
        pair: Pair<'_, Rule>,
    ) -> Result<(RelationshipPattern, NodePattern), ParseError> {
        let mut rel = None;
        let mut node = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::relationship_pattern => {
                    rel = Some(Self::build_relationship_pattern(inner)?);
                }
                Rule::node_pattern => {
                    node = Some(Self::build_node_pattern(inner)?);
                }
                _ => {}
            }
        }

        let rel = rel.ok_or_else(|| ParseError::MissingElement("relationship".to_string()))?;
        let node = node.ok_or_else(|| ParseError::MissingElement("node".to_string()))?;

        Ok((rel, node))
    }

    /// Build a node pattern.
    fn build_node_pattern(pair: Pair<'_, Rule>) -> Result<NodePattern, ParseError> {
        let mut variable = None;
        let mut labels = Vec::new();
        let mut properties = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::symbol => {
                    variable = Some(inner.as_str().to_string());
                }
                Rule::node_labels => {
                    labels = Self::build_node_labels(inner)?;
                }
                Rule::properties => {
                    properties = Some(Self::build_properties(inner)?);
                }
                _ => {}
            }
        }

        Ok(NodePattern {
            variable,
            labels,
            properties,
        })
    }

    /// Build node labels.
    fn build_node_labels(pair: Pair<'_, Rule>) -> Result<Vec<String>, ParseError> {
        let mut labels = Vec::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::node_label {
                let label = inner.into_inner().next().unwrap().as_str().to_string();
                labels.push(label);
            }
        }

        Ok(labels)
    }

    /// Build a relationship pattern.
    fn build_relationship_pattern(pair: Pair<'_, Rule>) -> Result<RelationshipPattern, ParseError> {
        let mut left_arrow = false;
        let mut right_arrow = false;
        let mut variable = None;
        let mut types = Vec::new();
        let mut length = None;
        let mut properties = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::left_arrow_head => left_arrow = true,
                Rule::right_arrow_head => right_arrow = true,
                Rule::rel_detail => {
                    for detail in inner.into_inner() {
                        match detail.as_rule() {
                            Rule::symbol => {
                                variable = Some(detail.as_str().to_string());
                            }
                            Rule::rel_types => {
                                types = Self::build_rel_types(detail)?;
                            }
                            Rule::range_literal => {
                                length = Some(Self::build_range_literal(detail)?);
                            }
                            Rule::properties => {
                                properties = Some(Self::build_properties(detail)?);
                            }
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
        }

        let direction = match (left_arrow, right_arrow) {
            (true, false) => RelationshipDirection::Incoming,
            (false, true) => RelationshipDirection::Outgoing,
            _ => RelationshipDirection::Both,
        };

        Ok(RelationshipPattern {
            variable,
            types,
            length,
            properties,
            direction,
        })
    }

    /// Build relationship types.
    fn build_rel_types(pair: Pair<'_, Rule>) -> Result<Vec<String>, ParseError> {
        let mut types = Vec::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::rel_type_name {
                let type_name = inner.into_inner().next().unwrap().as_str().to_string();
                types.push(type_name);
            }
        }

        Ok(types)
    }

    /// Build a range literal.
    fn build_range_literal(pair: Pair<'_, Rule>) -> Result<RelationshipLength, ParseError> {
        let input_str = pair.as_str();

        // Check if the input contains ".." to determine if it's a range
        let has_range = input_str.contains("..");

        // Collect all integer literals
        let mut integers = Vec::new();
        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::integer_literal {
                let n: u32 = inner.as_str().parse().unwrap_or(1);
                integers.push(n);
            }
        }

        // Interpret based on pattern and integers found
        let (min, max, min_explicit) = if has_range {
            // Pattern like *0..1 or *..5 or *0..
            if integers.is_empty() {
                // *.. means unbounded (min=1, max=None is default)
                (None, None, false)
            } else if integers.len() == 1 {
                // Could be *0.. or *..5
                if input_str.starts_with("*..") {
                    // *..5 means max=5, min defaults to 1
                    (None, Some(integers[0]), false)
                } else {
                    // *0.. means min=0, max unbounded
                    (Some(integers[0]), None, true)
                }
            } else {
                // *0..1 means min=0, max=1
                (Some(integers[0]), Some(integers[1]), true)
            }
        } else {
            // Pattern like *3 means exactly 3
            if integers.len() == 1 {
                (Some(integers[0]), Some(integers[0]), true)
            } else {
                (None, None, false)
            }
        };

        Ok(RelationshipLength::new_explicit(min, max, min_explicit))
    }

    /// Build properties.
    fn build_properties(pair: Pair<'_, Rule>) -> Result<Properties, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::map_literal => {
                let map = Self::build_map_literal(inner)?;
                Ok(Properties::Map(map))
            }
            Rule::parameter => {
                let param = Self::build_parameter(inner)?;
                Ok(Properties::Parameter(param))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "map or parameter".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a map literal.
    fn build_map_literal(pair: Pair<'_, Rule>) -> Result<IndexMap<String, Expression>, ParseError> {
        let mut map = IndexMap::new();

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::map_entry {
                let mut parts = inner.into_inner();
                let key_raw = parts.next().unwrap().as_str();
                let key = normalize_symbol(key_raw);
                let value = Self::build_expression(parts.next().unwrap())?;
                map.insert(key, value);
            }
        }

        Ok(map)
    }

    /// Build a parameter name.
    fn build_parameter(pair: Pair<'_, Rule>) -> Result<String, ParseError> {
        // Parameter is "$" followed by symbol or digits
        // Extract the name by stripping the leading $ and trimming whitespace
        let s = pair.as_str();
        if let Some(rest) = s.strip_prefix('$') {
            Ok(rest.trim().to_string())
        } else {
            Ok(s.trim().to_string())
        }
    }

    /// Build an expression.
    pub fn build_expression(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        match pair.as_rule() {
            Rule::expression => Self::build_expression(pair.into_inner().next().unwrap()),
            Rule::or_expression => Self::build_binary_expr(pair, BinaryOperator::Or),
            Rule::xor_expression => Self::build_binary_expr(pair, BinaryOperator::Xor),
            Rule::and_expression => Self::build_binary_expr(pair, BinaryOperator::And),
            Rule::not_expression => Self::build_not_expr(pair),
            Rule::comparison_expression => Self::build_comparison_expr(pair),
            Rule::in_expression => Self::build_in_expr(pair),
            Rule::add_subtract_expression => Self::build_add_subtract_expr(pair),
            Rule::multiply_divide_expression => Self::build_multiply_divide_expr(pair),
            Rule::power_expression => Self::build_binary_expr(pair, BinaryOperator::Power),
            Rule::unary_expression => Self::build_unary_expr(pair),
            Rule::string_list_null_predicate_expression => Self::build_predicate_expr(pair),
            Rule::property_or_labels_expression => Self::build_property_or_labels_expr(pair),
            Rule::atom => Self::build_atom(pair),
            Rule::property_expr => Self::build_property_expr(pair),
            _ => Err(ParseError::UnexpectedRule {
                expected: "expression".to_string(),
                found: format!("{:?}", pair.as_rule()),
            }),
        }
    }

    /// Build a binary expression.
    fn build_binary_expr(
        pair: Pair<'_, Rule>,
        op: BinaryOperator,
    ) -> Result<Expression, ParseError> {
        // Filter out operator tokens (OR, AND, XOR, etc.) - only keep expressions
        let parts: Vec<Pair<'_, Rule>> = pair
            .into_inner()
            .filter(|p| !Self::is_operator_token(p.as_rule()))
            .collect();

        if parts.is_empty() {
            return Err(ParseError::MissingElement("expression".to_string()));
        }

        let mut iter = parts.into_iter();
        let mut result = Self::build_expression(iter.next().unwrap())?;

        for part in iter {
            let right = Self::build_expression(part)?;
            result = Expression::BinaryOp(Box::new(result), op, Box::new(right));
        }

        Ok(result)
    }

    /// Check if a rule is an operator token that should be skipped
    fn is_operator_token(rule: Rule) -> bool {
        matches!(
            rule,
            Rule::OR
                | Rule::AND
                | Rule::XOR
                | Rule::NOT
                | Rule::IN
                | Rule::IS
                | Rule::STARTS
                | Rule::ENDS
                | Rule::CONTAINS
        )
    }

    /// Build a NOT expression.
    fn build_not_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut not_count = 0;
        let mut inner_expr = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::NOT => not_count += 1,
                _ => inner_expr = Some(Self::build_expression(inner)?),
            }
        }

        let mut result =
            inner_expr.ok_or_else(|| ParseError::MissingElement("expression".to_string()))?;
        for _ in 0..not_count {
            result = Expression::UnaryOp(UnaryOperator::Not, Box::new(result));
        }

        Ok(result)
    }

    /// Build a comparison expression.
    fn build_comparison_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair.into_inner().collect();

        if parts.len() == 1 {
            return Self::build_expression(parts.remove(0));
        }

        // For chained comparisons like `1 < n.num < 3`, we need to:
        // 1. Build (1 < n.num)
        // 2. Build (n.num < 3)
        // 3. AND them together: (1 < n.num) AND (n.num < 3)

        let mut left = Self::build_expression(parts.remove(0))?;
        let mut comparisons = Vec::new();

        while !parts.is_empty() {
            let partial = parts.remove(0);
            let mut partial_inner = partial.into_inner();
            let op_pair = partial_inner.next().unwrap();
            let op = match op_pair.as_str() {
                "=" => BinaryOperator::Equal,
                "<>" => BinaryOperator::NotEqual,
                "<" => BinaryOperator::LessThan,
                "<=" => BinaryOperator::LessThanOrEqual,
                ">" => BinaryOperator::GreaterThan,
                ">=" => BinaryOperator::GreaterThanOrEqual,
                _ => BinaryOperator::Equal,
            };
            let right = Self::build_expression(partial_inner.next().unwrap())?;

            // Build comparison: left op right
            let comparison = Expression::BinaryOp(Box::new(left.clone()), op, Box::new(right.clone()));
            comparisons.push(comparison);

            // The right operand becomes the left operand for the next comparison
            left = right;
        }

        // If we have a single comparison, return it
        if comparisons.len() == 1 {
            return Ok(comparisons.into_iter().next().unwrap());
        }

        // If we have multiple comparisons, AND them together
        let mut result = comparisons.remove(0);
        for comparison in comparisons {
            result = Expression::BinaryOp(Box::new(result), BinaryOperator::And, Box::new(comparison));
        }

        Ok(result)
    }

    /// Build an IN expression: expr IN expr
    fn build_in_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair
            .into_inner()
            .filter(|p| p.as_rule() != Rule::IN)
            .collect();

        if parts.len() == 1 {
            return Self::build_expression(parts.remove(0));
        }

        // Should have exactly 2 parts: left IN right
        let left = Self::build_expression(parts.remove(0))?;
        let right = Self::build_expression(parts.remove(0))?;

        Ok(Expression::InPredicate(Box::new(left), Box::new(right)))
    }

    /// Build an add/subtract expression.
    fn build_add_subtract_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair.into_inner().collect();

        if parts.len() == 1 {
            return Self::build_expression(parts.remove(0));
        }

        let mut result = Self::build_expression(parts.remove(0))?;

        while !parts.is_empty() {
            let op_pair = parts.remove(0);
            let op = match op_pair.as_rule() {
                Rule::PLUS => BinaryOperator::Add,
                Rule::MINUS => BinaryOperator::Subtract,
                _ => {
                    let right = Self::build_expression(op_pair)?;
                    result = Expression::BinaryOp(
                        Box::new(result),
                        BinaryOperator::Add,
                        Box::new(right),
                    );
                    continue;
                }
            };

            if !parts.is_empty() {
                let right = Self::build_expression(parts.remove(0))?;
                result = Expression::BinaryOp(Box::new(result), op, Box::new(right));
            }
        }

        Ok(result)
    }

    /// Build a multiply/divide expression.
    fn build_multiply_divide_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair.into_inner().collect();

        if parts.len() == 1 {
            return Self::build_expression(parts.remove(0));
        }

        let mut result = Self::build_expression(parts.remove(0))?;

        while !parts.is_empty() {
            let op_pair = parts.remove(0);
            let op = match op_pair.as_rule() {
                Rule::MULT => BinaryOperator::Multiply,
                Rule::DIV => BinaryOperator::Divide,
                Rule::MOD => BinaryOperator::Modulo,
                _ => {
                    let right = Self::build_expression(op_pair)?;
                    result = Expression::BinaryOp(
                        Box::new(result),
                        BinaryOperator::Multiply,
                        Box::new(right),
                    );
                    continue;
                }
            };

            if !parts.is_empty() {
                let right = Self::build_expression(parts.remove(0))?;
                result = Expression::BinaryOp(Box::new(result), op, Box::new(right));
            }
        }

        Ok(result)
    }

    /// Build a unary expression.
    fn build_unary_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut ops = Vec::new();
        let mut inner_pair = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::PLUS => ops.push(UnaryOperator::Positive),
                Rule::MINUS => ops.push(UnaryOperator::Negate),
                _ => inner_pair = Some(inner),
            }
        }

        let inner = inner_pair.ok_or_else(|| ParseError::MissingElement("expression".to_string()))?;

        // Special handling for i64::MIN: when we have exactly one negation and the
        // inner expression would overflow as an integer, check for i64::MIN representations
        if ops.len() == 1 && matches!(ops[0], UnaryOperator::Negate) {
            if let Some(literal_value) = Self::try_extract_overflow_integer(&inner) {
                let lower = literal_value.to_lowercase();
                // Check for i64::MIN in different bases:
                // - Decimal: 9223372036854775808
                // - Hex: 0x8000000000000000
                // - Octal: 0o1000000000000000000000
                if literal_value == "9223372036854775808"
                    || lower == "0x8000000000000000"
                    || lower == "0o1000000000000000000000"
                {
                    return Ok(Expression::Literal(Literal::Integer(i64::MIN)));
                }
            }
        }

        let mut result = Self::build_expression(inner)?;
        for op in ops.into_iter().rev() {
            result = Expression::UnaryOp(op, Box::new(result));
        }

        Ok(result)
    }

    /// Try to extract the string value of an integer literal that would overflow.
    /// Returns None if the pair doesn't represent a simple integer literal path.
    fn try_extract_overflow_integer(pair: &Pair<'_, Rule>) -> Option<String> {
        // Navigate through the expression hierarchy to find an atom/literal
        fn find_number_literal(pair: &Pair<'_, Rule>) -> Option<String> {
            match pair.as_rule() {
                Rule::number_literal => Some(pair.as_str().to_string()),
                Rule::literal => {
                    for inner in pair.clone().into_inner() {
                        if let Some(s) = find_number_literal(&inner) {
                            return Some(s);
                        }
                    }
                    None
                }
                Rule::atom => {
                    for inner in pair.clone().into_inner() {
                        if let Some(s) = find_number_literal(&inner) {
                            return Some(s);
                        }
                    }
                    None
                }
                Rule::property_or_labels_expression | Rule::string_list_null_predicate_expression => {
                    for inner in pair.clone().into_inner() {
                        if let Some(s) = find_number_literal(&inner) {
                            return Some(s);
                        }
                    }
                    None
                }
                _ => None,
            }
        }
        find_number_literal(pair)
    }

    /// Build a predicate expression.
    fn build_predicate_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut parts: Vec<Pair<'_, Rule>> = pair.into_inner().collect();

        if parts.len() == 1 {
            return Self::build_expression(parts.remove(0));
        }

        let base = Self::build_expression(parts.remove(0))?;
        let predicate = parts.remove(0);

        Self::build_predicate(base, predicate)
    }

    /// Build a predicate.
    fn build_predicate(
        base: Expression,
        predicate: Pair<'_, Rule>,
    ) -> Result<Expression, ParseError> {
        let inner = predicate.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::string_predicate => {
                let mut pred_type = StringPredicateOp::Contains;
                let mut right_expr = None;

                for p in inner.into_inner() {
                    match p.as_rule() {
                        Rule::STARTS => pred_type = StringPredicateOp::StartsWith,
                        Rule::ENDS => pred_type = StringPredicateOp::EndsWith,
                        Rule::CONTAINS => pred_type = StringPredicateOp::Contains,
                        Rule::REGEX_MATCH => {
                            // Regex match uses =~ operator
                            right_expr =
                                Some(Self::build_expression(p.into_inner().next().unwrap())?);
                            return Ok(Expression::BinaryOp(
                                Box::new(base),
                                BinaryOperator::RegexMatch,
                                Box::new(right_expr.unwrap()),
                            ));
                        }
                        Rule::property_or_labels_expression => {
                            right_expr = Some(Self::build_expression(p)?);
                        }
                        _ => {}
                    }
                }

                let right = right_expr.ok_or_else(|| {
                    ParseError::MissingElement("predicate expression".to_string())
                })?;
                Ok(Expression::StringPredicate(
                    Box::new(base),
                    pred_type,
                    Box::new(right),
                ))
            }
            Rule::null_predicate => {
                let mut is_null = true;
                for p in inner.into_inner() {
                    if p.as_rule() == Rule::NOT {
                        is_null = false;
                    }
                }
                Ok(Expression::NullPredicate(Box::new(base), is_null))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "predicate".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a property expression (atom followed by property lookups).
    fn build_property_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut base = None;
        let mut properties = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::atom => {
                    base = Some(Self::build_atom(inner)?);
                }
                Rule::property_lookup => {
                    let prop_raw = inner.into_inner().next().unwrap().as_str();
                    let prop = normalize_symbol(prop_raw);
                    properties.push(prop);
                }
                _ => {}
            }
        }

        let mut result = base.ok_or_else(|| ParseError::MissingElement("atom".to_string()))?;

        for prop in properties {
            result = Expression::PropertyAccess(Box::new(result), prop);
        }

        Ok(result)
    }

    /// Build a property or labels expression.
    fn build_property_or_labels_expr(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut base = None;
        let mut accessors: Vec<Accessor> = Vec::new();
        let mut labels = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::atom => {
                    base = Some(Self::build_atom(inner)?);
                }
                Rule::property_lookup => {
                    let prop_raw = inner.into_inner().next().unwrap().as_str();
                    let prop = normalize_symbol(prop_raw);
                    accessors.push(Accessor::Property(prop));
                }
                Rule::bracket_access => {
                    let bracket_contents = inner.into_inner().next().unwrap();
                    let contents_inner = bracket_contents.into_inner().next().unwrap();
                    match contents_inner.as_rule() {
                        Rule::slice_expression => {
                            let full_text = contents_inner.as_str();
                            let mut expressions = Vec::new();

                            for slice_part in contents_inner.into_inner() {
                                if slice_part.as_rule() == Rule::bracket_expression {
                                    expressions.push(Self::build_bracket_expression(slice_part)?);
                                }
                            }

                            // Determine start and end based on ".." position
                            let start;
                            let end;

                            if full_text.starts_with("..") {
                                // [..n] form: no start, end is the expression
                                start = None;
                                end = expressions.into_iter().next();
                            } else if full_text.ends_with("..") || !full_text.contains("..") {
                                // [n..] form: start is the expression, no end
                                start = expressions.into_iter().next();
                                end = None;
                            } else {
                                // [n..m] form: both present
                                let mut iter = expressions.into_iter();
                                start = iter.next();
                                end = iter.next();
                            }

                            accessors.push(Accessor::Slice(start, end));
                        }
                        Rule::bracket_expression => {
                            let index_expr = Self::build_bracket_expression(contents_inner)?;
                            accessors.push(Accessor::Index(index_expr));
                        }
                        _ => {}
                    }
                }
                Rule::node_labels => {
                    labels = Self::build_node_labels(inner)?;
                }
                _ => {}
            }
        }

        let mut result = base.ok_or_else(|| ParseError::MissingElement("atom".to_string()))?;

        for accessor in accessors {
            match accessor {
                Accessor::Property(prop) => {
                    result = Expression::PropertyAccess(Box::new(result), prop);
                }
                Accessor::Index(index_expr) => {
                    result = Expression::IndexAccess(Box::new(result), Box::new(index_expr));
                }
                Accessor::Slice(start, end) => {
                    result = Expression::ListSlice(
                        Box::new(result),
                        start.map(Box::new),
                        end.map(Box::new),
                    );
                }
            }
        }

        if !labels.is_empty() {
            result = Expression::LabelCheck(Box::new(result), labels);
        }

        Ok(result)
    }

    /// Build a bracket expression (restricted expression for inside brackets).
    /// bracket_expression = { bracket_unary ~ ((PLUS | MINUS | MULT | DIV | MOD) ~ bracket_unary)* }
    fn build_bracket_expression(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut inner = pair.into_inner();
        let first = inner.next().unwrap();
        let mut result = Self::build_bracket_unary(first)?;

        while let Some(op_pair) = inner.next() {
            let op = match op_pair.as_rule() {
                Rule::PLUS => BinaryOperator::Add,
                Rule::MINUS => BinaryOperator::Subtract,
                Rule::MULT => BinaryOperator::Multiply,
                Rule::DIV => BinaryOperator::Divide,
                Rule::MOD => BinaryOperator::Modulo,
                _ => continue,
            };
            let right_pair = inner.next().unwrap();
            let right = Self::build_bracket_unary(right_pair)?;
            result = Expression::BinaryOp(Box::new(result), op, Box::new(right));
        }

        Ok(result)
    }

    /// Build a bracket unary expression.
    /// bracket_unary = { (PLUS | MINUS)? ~ bracket_atom }
    fn build_bracket_unary(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut inner = pair.into_inner();
        let first = inner.next().unwrap();

        match first.as_rule() {
            Rule::PLUS => Self::build_bracket_atom(inner.next().unwrap()),
            Rule::MINUS => {
                let operand = Self::build_bracket_atom(inner.next().unwrap())?;
                Ok(Expression::UnaryOp(UnaryOperator::Negate, Box::new(operand)))
            }
            _ => Self::build_bracket_atom(first),
        }
    }

    /// Build a bracket atom.
    /// bracket_atom = { literal | parameter | function_invocation | parenthesized_expression | variable }
    fn build_bracket_atom(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::literal => Self::build_literal(inner),
            Rule::parameter => {
                let name = Self::build_parameter(inner)?;
                Ok(Expression::Parameter(name))
            }
            Rule::function_invocation => Self::build_function_invocation(inner),
            Rule::parenthesized_expression => {
                // Wrap in Parenthesized to preserve column name formatting
                let inner_expr = Self::build_expression(inner.into_inner().next().unwrap())?;
                Ok(Expression::Parenthesized(Box::new(inner_expr)))
            }
            Rule::variable => {
                let name = inner.into_inner().next().unwrap().as_str().to_string();
                Ok(Expression::Variable(name))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "bracket_atom".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build an atom.
    fn build_atom(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::literal => Self::build_literal(inner),
            Rule::parameter => {
                let name = Self::build_parameter(inner)?;
                Ok(Expression::Parameter(name))
            }
            Rule::case_expression => Self::build_case_expression(inner),
            Rule::count_all => Ok(Expression::CountAll),
            Rule::list_comprehension => Self::build_list_comprehension(inner),
            Rule::pattern_comprehension => Self::build_pattern_comprehension(inner),
            Rule::reduce_expression => Self::build_reduce_expression(inner),
            Rule::quantifier => Self::build_quantifier(inner),
            Rule::all_expression
            | Rule::any_expression
            | Rule::none_expression
            | Rule::single_expression => Self::build_quantifier_expression(inner),
            Rule::function_invocation => Self::build_function_invocation(inner),
            Rule::existential_subquery => Self::build_existential_subquery(inner),
            Rule::parenthesized_expression => {
                // Wrap in Parenthesized to preserve column name formatting
                let inner_expr = Self::build_expression(inner.into_inner().next().unwrap())?;
                Ok(Expression::Parenthesized(Box::new(inner_expr)))
            }
            Rule::variable => {
                let name = inner.into_inner().next().unwrap().as_str().to_string();
                Ok(Expression::Variable(name))
            }
            Rule::relationships_pattern => {
                // Pattern predicate in WHERE clause: (a)-[:T]->(b)
                let pattern = Self::build_relationships_pattern(inner)?;
                Ok(Expression::PatternPredicate(pattern))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "atom".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Build a relationships pattern (for pattern predicates).
    fn build_relationships_pattern(pair: Pair<'_, Rule>) -> Result<Pattern, ParseError> {
        // relationships_pattern = { node_pattern ~ pattern_element_chain+ }
        let mut inner = pair.into_inner();

        let start_node = inner
            .next()
            .ok_or_else(|| ParseError::MissingElement("node pattern".to_string()))?;
        let start = Self::build_node_pattern(start_node)?;

        let mut chain = Vec::new();
        for element in inner {
            if element.as_rule() == Rule::pattern_element_chain {
                let (rel, node) = Self::build_pattern_element_chain(element)?;
                chain.push((rel, node));
            }
        }

        let pattern_chain = PatternChain { start, chain };
        let part = PatternPart {
            variable: None,
            element: PatternElement::Chain(pattern_chain),
        };

        Ok(Pattern::new(vec![part]))
    }

    /// Build a literal.
    fn build_literal(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::number_literal => {
                let s = inner.as_str();
                // Check for hex/octal prefix first - 'e' and 'E' are valid hex digits, not exponents
                let s_lower = s.to_lowercase();
                let is_hex_or_octal = s_lower.contains("0x") || s_lower.contains("0o");
                // Only treat as float if it has decimal point or exponent AND is not hex/octal
                if !is_hex_or_octal && (s.contains('.') || s.contains('e') || s.contains('E')) {
                    let f: f64 = s
                        .parse()
                        .map_err(|_| ParseError::MissingElement("float".to_string()))?;
                    Ok(Expression::Literal(Literal::Float(f)))
                } else {
                    // Handle different integer formats
                    let (is_negative, num_str) = if let Some(rest) = s.strip_prefix('-') {
                        (true, rest)
                    } else {
                        (false, s)
                    };

                    // Parse integer with radix-specific handling and i64::MIN edge case support
                    let final_value: i64 = if num_str.starts_with("0x") || num_str.starts_with("0X") {
                        // Parse hex
                        match i64::from_str_radix(&num_str[2..], 16) {
                            Ok(v) => if is_negative { -v } else { v },
                            Err(e) if e.kind() == &std::num::IntErrorKind::PosOverflow && is_negative => {
                                // Check for i64::MIN edge case: -0x8000000000000000
                                if let Ok(u_val) = u64::from_str_radix(&num_str[2..], 16) {
                                    if u_val == 0x8000000000000000u64 {  // i64::MAX + 1
                                        i64::MIN
                                    } else {
                                        return Err(ParseError::IntegerOverflow(s.to_string()));
                                    }
                                } else {
                                    return Err(ParseError::IntegerOverflow(s.to_string()));
                                }
                            }
                            Err(_) => return Err(ParseError::IntegerOverflow(s.to_string())),
                        }
                    } else if num_str.starts_with("0o") || num_str.starts_with("0O") {
                        // Parse octal
                        match i64::from_str_radix(&num_str[2..], 8) {
                            Ok(v) => if is_negative { -v } else { v },
                            Err(e) if e.kind() == &std::num::IntErrorKind::PosOverflow && is_negative => {
                                // Check for i64::MIN edge case in octal
                                if let Ok(u_val) = u64::from_str_radix(&num_str[2..], 8) {
                                    if u_val == 0o1000000000000000000000u64 {
                                        i64::MIN
                                    } else {
                                        return Err(ParseError::IntegerOverflow(s.to_string()));
                                    }
                                } else {
                                    return Err(ParseError::IntegerOverflow(s.to_string()));
                                }
                            }
                            Err(_) => return Err(ParseError::IntegerOverflow(s.to_string())),
                        }
                    } else if num_str.starts_with("0b") || num_str.starts_with("0B") {
                        // Parse binary
                        match i64::from_str_radix(&num_str[2..], 2) {
                            Ok(v) => if is_negative { -v } else { v },
                            Err(_) => return Err(ParseError::IntegerOverflow(s.to_string())),
                        }
                    } else {
                        // Parse decimal
                        match num_str.parse::<i64>() {
                            Ok(v) => if is_negative { -v } else { v },
                            Err(e) if e.kind() == &std::num::IntErrorKind::PosOverflow && is_negative => {
                                // Check for i64::MIN edge case: -9223372036854775808
                                if num_str == "9223372036854775808" {
                                    i64::MIN
                                } else {
                                    return Err(ParseError::IntegerOverflow(s.to_string()));
                                }
                            }
                            Err(_) => return Err(ParseError::IntegerOverflow(s.to_string())),
                        }
                    };

                    Ok(Expression::Literal(Literal::Integer(final_value)))
                }
            }
            Rule::string_literal => {
                let s = inner.as_str();
                // Remove quotes and handle escapes
                let content = &s[1..s.len() - 1];
                let unescaped = Self::unescape_string(content);
                Ok(Expression::Literal(Literal::String(unescaped)))
            }
            Rule::boolean_literal => {
                let b = inner.into_inner().next().unwrap();
                match b.as_rule() {
                    Rule::TRUE => Ok(Expression::Literal(Literal::Boolean(true))),
                    Rule::FALSE => Ok(Expression::Literal(Literal::Boolean(false))),
                    _ => Err(ParseError::UnexpectedRule {
                        expected: "boolean".to_string(),
                        found: format!("{:?}", b.as_rule()),
                    }),
                }
            }
            Rule::null_literal => Ok(Expression::Literal(Literal::Null)),
            Rule::map_literal => {
                let map = Self::build_map_literal(inner)?;
                Ok(Expression::Map(map))
            }
            Rule::list_literal => {
                let mut items = Vec::new();
                for item in inner.into_inner() {
                    items.push(Self::build_expression(item)?);
                }
                Ok(Expression::List(items))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "literal".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }

    /// Unescape a string literal.
    fn unescape_string(s: &str) -> String {
        let mut result = String::new();
        let mut chars = s.chars().peekable();

        while let Some(c) = chars.next() {
            if c == '\\' {
                if let Some(&next) = chars.peek() {
                    chars.next();
                    match next {
                        'n' => result.push('\n'),
                        'r' => result.push('\r'),
                        't' => result.push('\t'),
                        '\\' => result.push('\\'),
                        '\'' => result.push('\''),
                        '"' => result.push('"'),
                        '/' => result.push('/'),
                        'b' => result.push('\x08'),
                        'f' => result.push('\x0C'),
                        'u' => {
                            // Unicode escape: \uXXXX
                            let mut hex = String::new();
                            for _ in 0..4 {
                                if let Some(&h) = chars.peek() {
                                    if h.is_ascii_hexdigit() {
                                        hex.push(chars.next().unwrap());
                                    }
                                }
                            }
                            if let Ok(code) = u32::from_str_radix(&hex, 16) {
                                if let Some(ch) = char::from_u32(code) {
                                    result.push(ch);
                                }
                            }
                        }
                        _ => {
                            result.push('\\');
                            result.push(next);
                        }
                    }
                }
            } else {
                result.push(c);
            }
        }

        result
    }

    /// Build a CASE expression.
    fn build_case_expression(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut operand = None;
        let mut alternatives = Vec::new();
        let mut default = None;
        let mut expect_operand = true;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::expression if expect_operand => {
                    operand = Some(Box::new(Self::build_expression(inner)?));
                    expect_operand = false;
                }
                Rule::case_alternatives => {
                    expect_operand = false;
                    // Find expression children (skip WHEN and THEN keywords)
                    let expressions: Vec<_> = inner
                        .into_inner()
                        .filter(|p| p.as_rule() == Rule::expression)
                        .collect();
                    if expressions.len() >= 2 {
                        let when = Self::build_expression(expressions[0].clone())?;
                        let then = Self::build_expression(expressions[1].clone())?;
                        alternatives.push((when, then));
                    }
                }
                Rule::else_clause => {
                    // Find expression child (skip ELSE keyword)
                    if let Some(expr) = find_child(inner, Rule::expression) {
                        default = Some(Box::new(Self::build_expression(expr)?));
                    }
                }
                _ => {}
            }
        }

        Ok(Expression::Case(CaseExpression {
            operand,
            alternatives,
            default,
        }))
    }

    /// Build a list comprehension.
    fn build_list_comprehension(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut variable = None;
        let mut list = None;
        let mut filter = None;
        let mut projection = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::filter_expression => {
                    for f in inner.into_inner() {
                        match f.as_rule() {
                            Rule::symbol => {
                                variable = Some(f.as_str().to_string());
                            }
                            Rule::expression => {
                                if list.is_none() {
                                    list = Some(Box::new(Self::build_expression(f)?));
                                } else {
                                    filter = Some(Box::new(Self::build_expression(f)?));
                                }
                            }
                            _ => {}
                        }
                    }
                }
                Rule::expression => {
                    projection = Some(Box::new(Self::build_expression(inner)?));
                }
                _ => {}
            }
        }

        let variable =
            variable.ok_or_else(|| ParseError::MissingElement("variable".to_string()))?;
        let list = list.ok_or_else(|| ParseError::MissingElement("list".to_string()))?;

        Ok(Expression::ListComprehension(ListComprehension {
            variable,
            list,
            filter,
            projection,
        }))
    }

    /// Build a pattern comprehension.
    fn build_pattern_comprehension(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut variable = None;
        let mut pattern = None;
        let mut filter = None;
        let mut projection = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::symbol => {
                    variable = Some(inner.as_str().to_string());
                }
                Rule::relationships_pattern => {
                    pattern = Some(Self::build_relationships_pattern(inner)?);
                }
                Rule::where_clause => {
                    if let Some(expr) = get_where_expression(inner) {
                        filter = Some(Box::new(Self::build_expression(expr)?));
                    }
                }
                Rule::expression => {
                    projection = Some(Box::new(Self::build_expression(inner)?));
                }
                _ => {}
            }
        }

        let pattern = pattern.ok_or_else(|| ParseError::MissingElement("pattern".to_string()))?;
        let projection =
            projection.ok_or_else(|| ParseError::MissingElement("projection".to_string()))?;

        Ok(Expression::PatternComprehension(PatternComprehension {
            variable,
            pattern,
            filter,
            projection,
        }))
    }


    /// Build a reduce expression.
    fn build_reduce_expression(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut symbols = Vec::new();
        let mut expressions = Vec::new();

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::symbol => {
                    symbols.push(inner.as_str().to_string());
                }
                Rule::expression => {
                    expressions.push(Self::build_expression(inner)?);
                }
                _ => {}
            }
        }

        if symbols.len() >= 2 && expressions.len() >= 3 {
            Ok(Expression::Reduce(ReduceExpression {
                accumulator: symbols[0].clone(),
                init: Box::new(expressions[0].clone()),
                variable: symbols[1].clone(),
                list: Box::new(expressions[1].clone()),
                expression: Box::new(expressions[2].clone()),
            }))
        } else {
            Err(ParseError::MissingElement("reduce parts".to_string()))
        }
    }

    /// Build a quantifier (ALL/ANY/NONE/SINGLE in filter_expression).
    fn build_quantifier(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        // The quantifier rule contains: keyword ~ "(" ~ filter_expression ~ ")"
        // We need to extract the keyword and filter_expression
        let mut quantifier = QuantifierType::All;
        let mut variable = None;
        let mut list = None;
        let mut condition = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::ALL => quantifier = QuantifierType::All,
                Rule::ANY_KW => quantifier = QuantifierType::Any,
                Rule::NONE => quantifier = QuantifierType::None,
                Rule::SINGLE => quantifier = QuantifierType::Single,
                Rule::filter_expression => {
                    for f in inner.into_inner() {
                        match f.as_rule() {
                            Rule::symbol => {
                                variable = Some(f.as_str().to_string());
                            }
                            Rule::expression => {
                                if list.is_none() {
                                    list = Some(Box::new(Self::build_expression(f)?));
                                } else {
                                    condition = Some(Box::new(Self::build_expression(f)?));
                                }
                            }
                            _ => {}
                        }
                    }
                }
                _ => {}
            }
        }

        let variable =
            variable.ok_or_else(|| ParseError::MissingElement("variable".to_string()))?;
        let list = list.ok_or_else(|| ParseError::MissingElement("list".to_string()))?;
        let condition =
            condition.ok_or_else(|| ParseError::MissingElement("condition".to_string()))?;

        Ok(Expression::Quantifier(QuantifierExpression {
            quantifier,
            variable,
            list,
            condition,
        }))
    }

    /// Build a quantifier expression.
    fn build_quantifier_expression(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let quantifier = match pair.as_rule() {
            Rule::all_expression => QuantifierType::All,
            Rule::any_expression => QuantifierType::Any,
            Rule::none_expression => QuantifierType::None,
            Rule::single_expression => QuantifierType::Single,
            _ => QuantifierType::All,
        };

        let mut variable = None;
        let mut list = None;
        let mut condition = None;

        for inner in pair.into_inner() {
            if inner.as_rule() == Rule::filter_expression {
                for f in inner.into_inner() {
                    match f.as_rule() {
                        Rule::symbol => {
                            variable = Some(f.as_str().to_string());
                        }
                        Rule::expression => {
                            if list.is_none() {
                                list = Some(Box::new(Self::build_expression(f)?));
                            } else {
                                condition = Some(Box::new(Self::build_expression(f)?));
                            }
                        }
                        _ => {}
                    }
                }
            }
        }

        let variable =
            variable.ok_or_else(|| ParseError::MissingElement("variable".to_string()))?;
        let list = list.ok_or_else(|| ParseError::MissingElement("list".to_string()))?;
        let condition =
            condition.ok_or_else(|| ParseError::MissingElement("condition".to_string()))?;

        Ok(Expression::Quantifier(QuantifierExpression {
            quantifier,
            variable,
            list,
            condition,
        }))
    }

    /// Build a function invocation.
    fn build_function_invocation(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        let mut namespace = Vec::new();
        let mut name = String::new();
        let mut arguments = Vec::new();
        let mut distinct = false;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::function_name => {
                    for name_part in inner.into_inner() {
                        match name_part.as_rule() {
                            Rule::namespace => {
                                for ns in name_part.into_inner() {
                                    namespace.push(ns.as_str().to_string());
                                }
                            }
                            Rule::symbol => {
                                name = name_part.as_str().to_string();
                            }
                            _ => {}
                        }
                    }
                }
                Rule::DISTINCT => distinct = true,
                Rule::expression => {
                    arguments.push(Self::build_expression(inner)?);
                }
                _ => {}
            }
        }

        Ok(Expression::FunctionCall(FunctionCall {
            namespace,
            name,
            arguments,
            distinct,
        }))
    }

    /// Build an existential subquery.
    fn build_existential_subquery(pair: Pair<'_, Rule>) -> Result<Expression, ParseError> {
        // existential_subquery = { EXISTS ~ "{" ~ (regular_query | pattern ~ where_clause?) ~ "}" }
        // Skip the EXISTS keyword and braces, find the actual content
        // Collect pattern and optional where_clause
        let mut pattern_opt: Option<Pattern> = None;
        let mut where_clause_opt: Option<Expression> = None;

        for inner in pair.into_inner() {
            match inner.as_rule() {
                Rule::EXISTS => continue, // Skip the keyword
                Rule::regular_query => {
                    let query = Self::build_regular_query(inner)?;
                    return Ok(Expression::ExistsSubquery(Box::new(query)));
                }
                Rule::pattern => {
                    pattern_opt = Some(Self::build_pattern(inner)?);
                }
                Rule::where_clause => {
                    // Extract expression from WHERE clause
                    if let Some(expr) = inner.into_inner().find(|p| p.as_rule() == Rule::expression) {
                        where_clause_opt = Some(Self::build_expression(expr)?);
                    }
                }
                _ => {}
            }
        }

        // If we have a pattern, create the query
        if let Some(pattern) = pattern_opt {
            // Create MATCH clause with optional WHERE
            let mut match_clause = MatchClause::new(pattern);
            match_clause.where_clause = where_clause_opt;
            let return_clause = Clause::Return(ReturnClause::new(Projection::all()));
            let query = Query::single(SingleQuery::new(vec![Clause::Match(match_clause), return_clause]));
            return Ok(Expression::ExistsSubquery(Box::new(query)));
        }

        Err(ParseError::MissingElement("exists subquery content".to_string()))
    }

    /// Build a schema command.
    fn build_schema_command(pair: Pair<'_, Rule>) -> Result<SchemaCommand, ParseError> {
        let inner = pair.into_inner().next().unwrap();
        match inner.as_rule() {
            Rule::create_index => {
                let mut label = String::new();
                let mut property = String::new();
                for p in inner.into_inner() {
                    match p.as_rule() {
                        Rule::symbol => {
                            if label.is_empty() {
                                label = p.as_str().to_string();
                            }
                        }
                        Rule::property_key_name => {
                            property = p.as_str().to_string();
                        }
                        _ => {}
                    }
                }
                Ok(SchemaCommand::CreateIndex(CreateIndex { label, property }))
            }
            Rule::drop_index => {
                let mut label = String::new();
                let mut property = String::new();
                for p in inner.into_inner() {
                    match p.as_rule() {
                        Rule::symbol => label = p.as_str().to_string(),
                        Rule::property_key_name => property = p.as_str().to_string(),
                        _ => {}
                    }
                }
                Ok(SchemaCommand::DropIndex(DropIndex { label, property }))
            }
            _ => Err(ParseError::UnexpectedRule {
                expected: "schema command".to_string(),
                found: format!("{:?}", inner.as_rule()),
            }),
        }
    }
}

/// Helper enum for building property/index/slice accessors
enum Accessor {
    Property(String),
    Index(Expression),
    Slice(Option<Expression>, Option<Expression>),
}

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

    fn parse_and_build(query: &str) -> Result<Vec<Statement>, ParseError> {
        let pairs = parse(query)?;
        AstBuilder::build_script(pairs)
    }

    #[test]
    fn test_simple_match_return() {
        let result = parse_and_build("MATCH (n) RETURN n").unwrap();
        assert_eq!(result.len(), 1);
        if let Statement::Query(query) = &result[0] {
            assert_eq!(query.parts.len(), 1);
            assert_eq!(query.parts[0].clauses.len(), 2);
        } else {
            panic!("Expected query");
        }
    }

    #[test]
    fn test_match_with_label() {
        let result = parse_and_build("MATCH (n:Person) RETURN n.name").unwrap();
        if let Statement::Query(query) = &result[0] {
            if let Clause::Match(m) = &query.parts[0].clauses[0] {
                let part = &m.pattern.parts[0];
                if let PatternElement::Chain(chain) = &part.element {
                    assert_eq!(chain.start.labels, vec!["Person".to_string()]);
                }
            }
        }
    }

    #[test]
    fn test_create() {
        let result = parse_and_build("CREATE (n:Person {name: 'Alice'})").unwrap();
        if let Statement::Query(query) = &result[0] {
            assert!(matches!(&query.parts[0].clauses[0], Clause::Create(_)));
        }
    }

    #[test]
    fn test_where_clause() {
        let result = parse_and_build("MATCH (n) WHERE n.age > 21 RETURN n").unwrap();
        if let Statement::Query(query) = &result[0] {
            if let Clause::Match(m) = &query.parts[0].clauses[0] {
                assert!(m.where_clause.is_some());
            }
        }
    }

    #[test]
    fn test_expression_building() {
        let result = parse_and_build("RETURN 1 + 2 * 3").unwrap();
        if let Statement::Query(query) = &result[0] {
            if let Clause::Return(r) = &query.parts[0].clauses[0] {
                if let ProjectionItems::Explicit(items) = &r.projection.items {
                    // Should be 1 + (2 * 3) due to precedence
                    assert!(matches!(
                        &items[0].expression,
                        Expression::BinaryOp(_, BinaryOperator::Add, _)
                    ));
                }
            }
        }
    }
}
