//! Command builder system for constructing Command AST nodes
//!
//! This module provides a fluent API for building command trees programmatically.
//! Builders follow the same patterns as expression builders but for commands.

use std::rc::Rc;

use crate::tree::ast::clause::{
    Assignment, AssignmentClause, FromClause, Selection, SortExpression, SortOrder, TableAlias,
    TableReference,
};
use crate::tree::ast::command::{
    AggCommand, AppendCommand, Command, DropCommand, ExplodeCommand, FromCommand, JoinCommand,
    LetCommand, LimitCommand, LookupCommand, MatchCommand, NestCommand, ParseCommand, RowsCommand,
    SelectCommand, SortCommand, UnionCommand, UnnestCommand, WhereCommand, WindowCommand,
    WithinCommand,
};
use crate::tree::ast::expression::{ColumnReference, Expression};
use crate::tree::ast::identifier::{
    Identifier, ParsedIdentifier, ParsedSimpleIdentifier, SimpleIdentifier,
};
use crate::tree::ast::node::Span;
use crate::tree::ast::pattern::{Pattern, PatternKind, QuantifiedPattern, Quantifier};

use super::IntoExpressionBuilder;

// ============================================================================
// TableReference convenience functions
// ============================================================================

/// Create a TableReference from an identifier
pub fn table_ref(identifier: impl Into<Identifier>) -> TableReference {
    TableReference {
        span: Span::NONE,
        identifier: ParsedIdentifier::Valid(identifier.into()),
    }
}

// Implement Into<TableReference> for Identifier types
impl From<Identifier> for TableReference {
    fn from(identifier: Identifier) -> Self {
        table_ref(identifier)
    }
}

impl From<&str> for TableReference {
    fn from(s: &str) -> Self {
        table_ref(s)
    }
}

impl From<String> for TableReference {
    fn from(s: String) -> Self {
        table_ref(s)
    }
}

// ============================================================================
// Pattern convenience functions
// ============================================================================

/// Create a quantified pattern from a table reference (e.g., for MATCH commands)
///
/// Examples:
/// - `pattern_quantified(table_ref("events"), None)` - Simple pattern: `events`
/// - `pattern_quantified(table_ref("events"), Some(quantifier_at_least_one()))` - Pattern: `events+`
pub fn pattern_quantified(
    from_clause: impl Into<FromClause>,
    quantifier: Option<Quantifier>,
) -> Pattern {
    let kind: PatternKind = QuantifiedPattern {
        span: Span::NONE,
        from_clause: Rc::new(from_clause.into()),
        quantifier: quantifier.map(Rc::new),
    }
    .into();
    Pattern {
        span: Span::NONE,
        kind,
    }
}

/// Create an "at least one" quantifier (+)
pub fn quantifier_at_least_one() -> Quantifier {
    crate::tree::ast::pattern::QuantifierKind::AtLeastOne.into()
}

/// Create an "any number" quantifier (*)
pub fn quantifier_any_number() -> Quantifier {
    crate::tree::ast::pattern::QuantifierKind::AnyNumber.into()
}

/// Create a "zero or one" quantifier (?)
pub fn quantifier_zero_or_one() -> Quantifier {
    crate::tree::ast::pattern::QuantifierKind::ZeroOrOne.into()
}

/// Create a pattern with a table alias (e.g., e=events)
pub fn pattern_with_alias(
    alias: impl Into<SimpleIdentifier>,
    table: impl Into<Identifier>,
) -> Pattern {
    pattern_quantified(table_alias_from_clause(alias, table), None)
}

/// Create a pattern with a table alias and quantifier (e.g., e=events+)
pub fn pattern_with_alias_and_quantifier(
    alias: impl Into<SimpleIdentifier>,
    table: impl Into<Identifier>,
    quantifier: Quantifier,
) -> Pattern {
    pattern_quantified(table_alias_from_clause(alias, table), Some(quantifier))
}

/// Helper to create a TableAlias FromClause
fn table_alias_from_clause(
    alias: impl Into<SimpleIdentifier>,
    table: impl Into<Identifier>,
) -> FromClause {
    let alias_simple: SimpleIdentifier = alias.into();
    let table_ident: Identifier = table.into();
    FromClause::TableAlias(Rc::new(TableAlias {
        span: Span::NONE,
        alias: alias_simple.into(),
        table: TableReference {
            span: Span::NONE,
            identifier: table_ident.into(),
        },
    }))
}

/// Create an "exactly n" quantifier ({n})
pub fn quantifier_exactly(n: impl Into<String>) -> Quantifier {
    crate::tree::ast::pattern::QuantifierKind::Exactly(n.into()).into()
}

// Implement Into<Pattern> for common types
impl From<TableReference> for Pattern {
    fn from(table: TableReference) -> Self {
        pattern_quantified(table, None)
    }
}

impl From<&str> for Pattern {
    fn from(s: &str) -> Self {
        pattern_quantified(table_ref(s), None)
    }
}

impl From<String> for Pattern {
    fn from(s: String) -> Self {
        pattern_quantified(table_ref(s), None)
    }
}

/// Builder for LET command
#[derive(Debug)]
pub struct LetCommandBuilder {
    assignments: Vec<Assignment>,
    span: Span,
}

impl LetCommandBuilder {
    pub fn new() -> Self {
        Self {
            assignments: Vec::new(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a named field to the LET command
    pub fn named_field(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.assignments.push(Assignment {
            span: Span::NONE,
            identifier: ParsedIdentifier::Valid(identifier.into()),
            expression: Rc::new(expr),
        });
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: LetCommand {
                assignments: self.assignments.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for LetCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for WHERE command
#[derive(Debug)]
pub struct WhereCommandBuilder {
    condition: Expression,
    span: Span,
}

impl WhereCommandBuilder {
    pub fn new(condition: impl IntoExpressionBuilder) -> Self {
        Self {
            condition: condition.into_expression_builder().build(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: WhereCommand {
                condition: Rc::new(self.condition.clone()),
            }
            .into(),
        }
    }
}

/// Builder for SELECT command
#[derive(Debug)]
pub struct SelectCommandBuilder {
    clauses: Vec<AssignmentClause>,
    span: Span,
}

impl SelectCommandBuilder {
    pub fn new() -> Self {
        Self {
            clauses: Vec::new(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a named field (identifier = expression)
    pub fn named_field(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.clauses.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Add a column reference field (identifier inferred from column name)
    pub fn field(mut self, column: impl Into<ColumnReference>) -> Self {
        let col_ref = column.into();
        let identifier = col_ref.column_name.clone().into();
        let expr = Expression::from_kind(col_ref);
        self.clauses.push(
            Assignment {
                span: Span::NONE,
                identifier,
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: SelectCommand {
                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for SelectCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for DROP command
#[derive(Debug)]
pub struct DropCommandBuilder {
    selections: Vec<Selection>,
    span: Span,
}

impl DropCommandBuilder {
    pub fn new() -> Self {
        Self {
            selections: Vec::new(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a field to drop
    pub fn field(mut self, identifier: impl Into<Identifier>) -> Self {
        self.selections.push(Selection {
            span: Span::NONE,
            identifier: ParsedIdentifier::Valid(identifier.into()),
        });
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: DropCommand {
                selections: self.selections.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for DropCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for FROM command
#[derive(Debug)]
pub struct FromCommandBuilder {
    clauses: Vec<FromClause>,
    span: Span,
}

impl FromCommandBuilder {
    pub fn new() -> Self {
        Self {
            clauses: Vec::new(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a table alias (name = table_reference)
    pub fn table_alias(
        mut self,
        alias: impl Into<SimpleIdentifier>,
        table_reference: impl Into<Identifier>,
    ) -> Self {
        self.clauses.push(
            TableAlias {
                span: Span::NONE,
                alias: ParsedSimpleIdentifier::Valid(alias.into()),
                table: TableReference {
                    span: Span::NONE,
                    identifier: ParsedIdentifier::Valid(table_reference.into()),
                },
            }
            .into(),
        );
        self
    }

    /// Add a direct table reference
    pub fn table_reference(mut self, table_reference: impl Into<Identifier>) -> Self {
        self.clauses.push(
            TableReference {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(table_reference.into()),
            }
            .into(),
        );
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: FromCommand {
                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for FromCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for UNION command
#[derive(Debug)]
pub struct UnionCommandBuilder {
    clauses: Vec<FromClause>,
    span: Span,
}

impl UnionCommandBuilder {
    pub fn new() -> Self {
        Self {
            clauses: Vec::new(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a table alias
    pub fn table_alias(
        mut self,
        alias: impl Into<String>,
        table_reference: impl Into<Identifier>,
    ) -> Self {
        self.clauses.push(
            TableAlias {
                span: Span::NONE,
                alias: ParsedSimpleIdentifier::Valid(SimpleIdentifier::new(alias)),
                table: TableReference {
                    span: Span::NONE,
                    identifier: ParsedIdentifier::Valid(table_reference.into()),
                },
            }
            .into(),
        );
        self
    }

    /// Add a direct table reference
    pub fn table_reference(mut self, table_reference: impl Into<Identifier>) -> Self {
        self.clauses.push(
            TableReference {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(table_reference.into()),
            }
            .into(),
        );
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: UnionCommand {
                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for UnionCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for LIMIT command
#[derive(Debug)]
pub struct LimitCommandBuilder {
    count: Expression,
}

impl LimitCommandBuilder {
    pub fn new(count: impl IntoExpressionBuilder) -> Self {
        Self {
            count: count.into_expression_builder().build(),
        }
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: LimitCommand {
                count: Rc::new(self.count.clone()),
            }
            .into(),
        }
    }
}

/// Builder for WITHIN command
#[derive(Debug)]
pub struct WithinCommandBuilder {
    duration: Expression,
}

impl WithinCommandBuilder {
    pub fn new(duration: impl IntoExpressionBuilder) -> Self {
        Self {
            duration: duration.into_expression_builder().build(),
        }
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: WithinCommand {
                duration: Rc::new(self.duration.clone()),
            }
            .into(),
        }
    }
}

/// Builder for SORT command
#[derive(Debug)]
pub struct SortCommandBuilder {
    pub(crate) expressions: Vec<SortExpression>,
}

impl SortCommandBuilder {
    pub fn new() -> Self {
        Self {
            expressions: Vec::new(),
        }
    }

    /// Add a sort expression with no explicit order (database default)
    pub fn by(mut self, expression: impl IntoExpressionBuilder) -> Self {
        self.expressions.push(SortExpression {
            span: Span::NONE,
            expression: Rc::new(expression.into_expression_builder().build()),
            order: None,
        });
        self
    }

    /// Add an ascending sort expression
    pub fn asc(mut self, expression: impl IntoExpressionBuilder) -> Self {
        self.expressions.push(SortExpression {
            span: Span::NONE,
            expression: Rc::new(expression.into_expression_builder().build()),
            order: Some(SortOrder::Asc),
        });
        self
    }

    /// Add a descending sort expression
    pub fn desc(mut self, expression: impl IntoExpressionBuilder) -> Self {
        self.expressions.push(SortExpression {
            span: Span::NONE,
            expression: Rc::new(expression.into_expression_builder().build()),
            order: Some(SortOrder::Desc),
        });
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: SortCommand {
                expressions: self.expressions.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for SortCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

// Typestate markers for ParseCommandBuilder
pub struct NoPattern;
pub struct NoIdentifiers;
pub struct ValidParse;

/// Builder for PARSE command with compile-time safety
///
/// Uses typestate pattern to ensure pattern and at least one identifier are provided.
#[derive(Debug)]
pub struct ParseCommandBuilder<State = NoPattern> {
    source: Option<Expression>,
    pattern: Option<Expression>,
    identifiers: Vec<ParsedIdentifier>,
    nodrop: bool,
    _state: std::marker::PhantomData<State>,
}

impl ParseCommandBuilder<NoPattern> {
    pub fn new() -> Self {
        Self {
            source: None,
            pattern: None,
            identifiers: Vec::new(),
            nodrop: false,
            _state: std::marker::PhantomData,
        }
    }

    /// Set the pattern to parse (transitions to NoIdentifiers state)
    pub fn pattern(
        self,
        pattern: impl IntoExpressionBuilder,
    ) -> ParseCommandBuilder<NoIdentifiers> {
        ParseCommandBuilder {
            source: self.source,
            pattern: Some(pattern.into_expression_builder().build()),
            identifiers: self.identifiers,
            nodrop: self.nodrop,
            _state: std::marker::PhantomData,
        }
    }
}

impl Default for ParseCommandBuilder<NoPattern> {
    fn default() -> Self {
        Self::new()
    }
}

impl ParseCommandBuilder<NoIdentifiers> {
    /// Add an identifier to extract (transitions to ValidParse state)
    pub fn identifier(
        mut self,
        identifier: impl Into<Identifier>,
    ) -> ParseCommandBuilder<ValidParse> {
        self.identifiers
            .push(ParsedIdentifier::Valid(identifier.into()));
        ParseCommandBuilder {
            source: self.source,
            pattern: self.pattern,
            identifiers: self.identifiers,
            nodrop: self.nodrop,
            _state: std::marker::PhantomData,
        }
    }
}

impl ParseCommandBuilder<ValidParse> {
    /// Add another identifier to extract
    pub fn identifier(mut self, identifier: impl Into<Identifier>) -> Self {
        self.identifiers
            .push(ParsedIdentifier::Valid(identifier.into()));
        self
    }

    /// Set the source expression
    pub fn source(mut self, source: impl IntoExpressionBuilder) -> Self {
        self.source = Some(source.into_expression_builder().build());
        self
    }

    /// Set nodrop flag
    pub fn nodrop(mut self, nodrop: bool) -> Self {
        self.nodrop = nodrop;
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: ParseCommand {
                source: self.source.clone().map(Rc::new),
                pattern: Rc::new(
                    self.pattern
                        .clone()
                        .expect("pattern should be set in ValidParse state"),
                ),
                identifiers: self.identifiers.clone(),
                nodrop: self.nodrop,
            }
            .into(),
        }
    }
}

/// Builder for AGG command
#[derive(Debug)]
pub struct AggCommandBuilder {
    clauses: Vec<AssignmentClause>,
    group_by: Vec<AssignmentClause>,
    sort: Vec<SortExpression>,
    span: Span,
}

impl AggCommandBuilder {
    pub fn new() -> Self {
        Self {
            clauses: Vec::new(),
            group_by: Vec::new(),
            sort: Vec::new(),
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a named aggregation field
    pub fn named_aggregate(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.clauses.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Add a named group by field
    pub fn named_group(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.group_by.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Add a column reference to group by (identifier inferred from column name)
    pub fn group_by(mut self, column: impl Into<ColumnReference>) -> Self {
        let col_ref = column.into();
        let identifier = col_ref.column_name.clone().into();
        let expr = Expression::from_kind(col_ref);
        self.group_by.push(
            Assignment {
                span: Span::NONE,
                identifier,
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Set sort expressions using a SortCommandBuilder
    pub fn sort(mut self, sort_builder: SortCommandBuilder) -> Self {
        self.sort = sort_builder.expressions;
        self
    }

    /// Add a single sort expression
    pub fn sort_expr(mut self, sort_expr: SortExpression) -> Self {
        self.sort.push(sort_expr);
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: AggCommand {
                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
                group_by: self.group_by.iter().cloned().map(Rc::new).collect(),
                sort: self.sort.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

impl Default for AggCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for WINDOW command
#[derive(Debug)]
pub struct WindowCommandBuilder {
    clauses: Vec<AssignmentClause>,
    group_by: Vec<AssignmentClause>,
    sort: Vec<SortExpression>,
    within: Option<Expression>,
    span: Span,
}

impl WindowCommandBuilder {
    pub fn new() -> Self {
        Self {
            clauses: Vec::new(),
            group_by: Vec::new(),
            sort: Vec::new(),
            within: None,
            span: Span::NONE,
        }
    }

    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    /// Add a named window field
    pub fn named_field(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.clauses.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Add a named group by field
    pub fn group_by(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.group_by.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Set sort expressions using a SortCommandBuilder
    pub fn sort(mut self, sort_builder: SortCommandBuilder) -> Self {
        self.sort = sort_builder.expressions;
        self
    }

    /// Add a single sort expression
    pub fn sort_expr(mut self, sort_expr: SortExpression) -> Self {
        self.sort.push(sort_expr);
        self
    }

    /// Set within duration
    pub fn within(mut self, duration: impl IntoExpressionBuilder) -> Self {
        self.within = Some(duration.into_expression_builder().build());
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: WindowCommand {
                clauses: self.clauses.iter().cloned().map(Rc::new).collect(),
                group_by: self.group_by.iter().cloned().map(Rc::new).collect(),
                sort: self.sort.iter().cloned().map(Rc::new).collect(),
                within: self.within.clone().map(Rc::new),
            }
            .into(),
        }
    }
}

impl Default for WindowCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for APPEND command
#[derive(Debug)]
pub struct AppendCommandBuilder {
    table: TableReference,
    distinct_by: Vec<Selection>,
}

impl AppendCommandBuilder {
    pub fn new(table: impl Into<TableReference>) -> Self {
        Self {
            table: table.into(),
            distinct_by: Vec::new(),
        }
    }

    /// Add a distinct_by identifier
    pub fn distinct_by(mut self, identifier: impl Into<Identifier>) -> Self {
        self.distinct_by.push(Selection {
            span: Span::NONE,
            identifier: ParsedIdentifier::Valid(identifier.into()),
        });
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: AppendCommand {
                table: Rc::new(self.table.clone()),
                distinct_by: self.distinct_by.iter().cloned().map(Rc::new).collect(),
            }
            .into(),
        }
    }
}

/// Builder for JOIN command
#[derive(Debug)]
pub struct JoinCommandBuilder {
    other: FromClause,
    on: Option<Expression>,
}

impl JoinCommandBuilder {
    pub fn table_alias(
        alias: impl Into<SimpleIdentifier>,
        table_reference: impl Into<Identifier>,
    ) -> Self {
        Self {
            other: TableAlias {
                span: Span::NONE,
                alias: ParsedSimpleIdentifier::Valid(alias.into()),
                table: TableReference {
                    span: Span::NONE,
                    identifier: ParsedIdentifier::Valid(table_reference.into()),
                },
            }
            .into(),
            on: None,
        }
    }

    pub fn table_reference(table_reference: impl Into<Identifier>) -> Self {
        Self {
            other: TableReference {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(table_reference.into()),
            }
            .into(),
            on: None,
        }
    }

    /// Set the ON condition
    pub fn on(mut self, condition: impl IntoExpressionBuilder) -> Self {
        self.on = Some(condition.into_expression_builder().build());
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: JoinCommand {
                other: Rc::new(self.other.clone()),
                on_condition: self.on.clone().map(Rc::new),
            }
            .into(),
        }
    }
}

/// Builder for LOOKUP command
#[derive(Debug)]
pub struct LookupCommandBuilder {
    other: FromClause,
    on: Option<Expression>,
}

impl LookupCommandBuilder {
    pub fn table_alias(
        alias: impl Into<SimpleIdentifier>,
        table_reference: impl Into<Identifier>,
    ) -> Self {
        Self {
            other: TableAlias {
                span: Span::NONE,
                alias: ParsedSimpleIdentifier::Valid(alias.into()),
                table: TableReference {
                    span: Span::NONE,
                    identifier: ParsedIdentifier::Valid(table_reference.into()),
                },
            }
            .into(),
            on: None,
        }
    }

    pub fn table_reference(table_reference: impl Into<Identifier>) -> Self {
        Self {
            other: TableReference {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(table_reference.into()),
            }
            .into(),
            on: None,
        }
    }

    /// Set the ON condition
    pub fn on(mut self, condition: impl IntoExpressionBuilder) -> Self {
        self.on = Some(condition.into_expression_builder().build());
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: LookupCommand {
                other: Rc::new(self.other.clone()),
                on_condition: self.on.clone().map(Rc::new),
            }
            .into(),
        }
    }
}

// Typestate markers for ExplodeCommandBuilder
pub struct NoClause;
pub struct WithClause;

/// Builder for EXPLODE command with compile-time safety
///
/// Uses typestate pattern to ensure either expression() or assignment() is called.
#[derive(Debug)]
pub struct ExplodeCommandBuilder<State = NoClause> {
    clause: Option<AssignmentClause>,
    span: Span,
    _state: std::marker::PhantomData<State>,
}

impl ExplodeCommandBuilder<NoClause> {
    pub fn new() -> Self {
        Self {
            clause: None,
            span: Span::NONE,
            _state: std::marker::PhantomData,
        }
    }

    /// Set an assignment to explode (identifier = expression)
    pub fn named_field(
        self,
        identifier: impl Into<Identifier>,
        expr: impl IntoExpressionBuilder,
    ) -> ExplodeCommandBuilder<WithClause> {
        let expr = expr.into_expression_builder().build();
        ExplodeCommandBuilder {
            clause: Some(
                Assignment {
                    span: Span::NONE,
                    identifier: ParsedIdentifier::Valid(identifier.into()),
                    expression: Rc::new(expr),
                }
                .into(),
            ),
            span: self.span,
            _state: std::marker::PhantomData,
        }
    }

    /// Set a column reference to explode (identifier inferred from column name)
    pub fn field(self, column: impl Into<ColumnReference>) -> ExplodeCommandBuilder<WithClause> {
        let col_ref = column.into();
        let identifier = col_ref.column_name.clone().into();
        let expr = Expression::from_kind(col_ref);
        ExplodeCommandBuilder {
            clause: Some(
                Assignment {
                    span: Span::NONE,
                    identifier,
                    expression: Rc::new(expr),
                }
                .into(),
            ),
            span: self.span,
            _state: std::marker::PhantomData,
        }
    }
}

impl<State> ExplodeCommandBuilder<State> {
    /// Set the span for this command
    pub fn at(mut self, span: Span) -> Self {
        self.span = span;
        self
    }
}

impl Default for ExplodeCommandBuilder<NoClause> {
    fn default() -> Self {
        Self::new()
    }
}

impl ExplodeCommandBuilder<WithClause> {
    pub fn build(&self) -> Command {
        Command {
            span: self.span,
            kind: ExplodeCommand {
                clause: Rc::new(
                    self.clause
                        .clone()
                        .expect("clause should be set in WithClause state"),
                ),
            }
            .into(),
        }
    }
}

// Only implement From<Command> for the WithClause state
impl From<ExplodeCommandBuilder<WithClause>> for Command {
    fn from(value: ExplodeCommandBuilder<WithClause>) -> Self {
        value.build()
    }
}

/// Builder for UNNEST command
#[derive(Debug)]
pub struct UnnestCommandBuilder {
    expression: Expression,
}

impl UnnestCommandBuilder {
    pub fn new(expression: impl IntoExpressionBuilder) -> Self {
        Self {
            expression: expression.into_expression_builder().build(),
        }
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: UnnestCommand {
                expression: Rc::new(self.expression.clone()),
            }
            .into(),
        }
    }
}

/// Builder for ROWS command
#[derive(Debug)]
pub struct RowsCommandBuilder {
    expression: Expression,
}

impl RowsCommandBuilder {
    pub fn new(expression: impl IntoExpressionBuilder) -> Self {
        Self {
            expression: expression.into_expression_builder().build(),
        }
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: RowsCommand {
                expression: Rc::new(self.expression.clone()),
            }
            .into(),
        }
    }
}

/// Builder for NEST command
#[derive(Debug)]
pub struct NestCommandBuilder {
    identifier: ParsedIdentifier,
}

impl NestCommandBuilder {
    pub fn new(identifier: impl Into<Identifier>) -> Self {
        Self {
            identifier: ParsedIdentifier::Valid(identifier.into()),
        }
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: NestCommand {
                identifier: Rc::new(self.identifier.clone()),
            }
            .into(),
        }
    }
}

/// Builder for MATCH command
#[derive(Debug)]
pub struct MatchCommandBuilder {
    pattern: Vec<Pattern>,
    agg: Vec<AssignmentClause>,
    group_by: Vec<AssignmentClause>,
    sort: Vec<SortExpression>,
    within: Option<Expression>,
}

impl MatchCommandBuilder {
    pub fn new() -> Self {
        Self {
            pattern: Vec::new(),
            agg: Vec::new(),
            group_by: Vec::new(),
            sort: Vec::new(),
            within: None,
        }
    }

    /// Add a pattern
    pub fn pattern(mut self, pattern: impl Into<Pattern>) -> Self {
        self.pattern.push(pattern.into());
        self
    }

    /// Add a pattern with a table alias (e.g., e=events)
    pub fn named_pattern(
        mut self,
        alias: impl Into<SimpleIdentifier>,
        table: impl Into<Identifier>,
    ) -> Self {
        self.pattern.push(pattern_with_alias(alias, table));
        self
    }

    /// Add a pattern with a table alias and quantifier (e.g., e=events+)
    pub fn named_quantified_pattern(
        mut self,
        alias: impl Into<SimpleIdentifier>,
        table: impl Into<Identifier>,
        quantifier: Quantifier,
    ) -> Self {
        self.pattern
            .push(pattern_with_alias_and_quantifier(alias, table, quantifier));
        self
    }

    /// Add an agg clause (aggregation over matched rows)
    pub fn agg(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.agg.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Add a named group by field
    pub fn named_group(
        mut self,
        identifier: impl Into<Identifier>,
        expression: impl IntoExpressionBuilder,
    ) -> Self {
        let expr = expression.into_expression_builder().build();
        self.group_by.push(
            Assignment {
                span: Span::NONE,
                identifier: ParsedIdentifier::Valid(identifier.into()),
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Add a column reference to group by (identifier inferred from column name)
    pub fn group_by(mut self, column: impl Into<ColumnReference>) -> Self {
        let col_ref = column.into();
        let identifier = col_ref.column_name.clone().into();
        let expr = Expression::from_kind(col_ref);
        self.group_by.push(
            Assignment {
                span: Span::NONE,
                identifier,
                expression: Rc::new(expr),
            }
            .into(),
        );
        self
    }

    /// Set sort expressions using a SortCommandBuilder
    pub fn sort(mut self, sort_builder: SortCommandBuilder) -> Self {
        self.sort = sort_builder.expressions;
        self
    }

    /// Set the within expression
    pub fn within(mut self, expr: impl IntoExpressionBuilder) -> Self {
        self.within = Some(expr.into_expression_builder().build());
        self
    }

    pub fn build(&self) -> Command {
        Command {
            span: Span::NONE,
            kind: MatchCommand {
                pattern: self
                    .pattern
                    .iter()
                    .cloned()
                    .map(|pattern| Rc::new(pattern))
                    .collect(),
                agg: self.agg.iter().cloned().map(|s| Rc::new(s)).collect(),
                group_by: self
                    .group_by
                    .iter()
                    .cloned()
                    .map(|group_by| Rc::new(group_by))
                    .collect(),
                sort: self.sort.iter().map(|sort| Rc::new(sort.clone())).collect(),
                within: self.within.clone().map(Rc::new),
            }
            .into(),
        }
    }
}

impl Default for MatchCommandBuilder {
    fn default() -> Self {
        Self::new()
    }
}

// Convenience functions for creating command builders

/// Create a LET command builder
pub fn let_command() -> LetCommandBuilder {
    LetCommandBuilder::new()
}

/// Create a WHERE command builder
pub fn where_command(condition: impl IntoExpressionBuilder) -> WhereCommandBuilder {
    WhereCommandBuilder::new(condition)
}

/// Create a SELECT command builder
pub fn select_command() -> SelectCommandBuilder {
    SelectCommandBuilder::new()
}

/// Create a DROP command builder
pub fn drop_command() -> DropCommandBuilder {
    DropCommandBuilder::new()
}

/// Create a FROM command builder
pub fn from_command() -> FromCommandBuilder {
    FromCommandBuilder::new()
}

/// Create a UNION command builder
pub fn union_command() -> UnionCommandBuilder {
    UnionCommandBuilder::new()
}

/// Create a LIMIT command builder
pub fn limit_command(count: impl IntoExpressionBuilder) -> LimitCommandBuilder {
    LimitCommandBuilder::new(count)
}

/// Create a WITHIN command builder
pub fn within_command(duration: impl IntoExpressionBuilder) -> WithinCommandBuilder {
    WithinCommandBuilder::new(duration)
}

/// Create a SORT command builder
pub fn sort_command() -> SortCommandBuilder {
    SortCommandBuilder::new()
}

/// Create a PARSE command builder
pub fn parse_command() -> ParseCommandBuilder<NoPattern> {
    ParseCommandBuilder::new()
}

/// Create an AGG command builder
pub fn agg_command() -> AggCommandBuilder {
    AggCommandBuilder::new()
}

/// Create a WINDOW command builder
pub fn window_command() -> WindowCommandBuilder {
    WindowCommandBuilder::new()
}

/// Create an APPEND command builder
pub fn append_command(table: impl Into<TableReference>) -> AppendCommandBuilder {
    AppendCommandBuilder::new(table)
}

/// Create a JOIN command builder with table alias
pub fn join_table_alias(
    alias: impl Into<SimpleIdentifier>,
    table_reference: impl Into<Identifier>,
) -> JoinCommandBuilder {
    JoinCommandBuilder::table_alias(alias, table_reference)
}

/// Create a JOIN command builder with table reference
pub fn join_table_reference(table_reference: impl Into<Identifier>) -> JoinCommandBuilder {
    JoinCommandBuilder::table_reference(table_reference)
}

/// Create a LOOKUP command builder with table alias
pub fn lookup_table_alias(
    alias: impl Into<SimpleIdentifier>,
    table_reference: impl Into<Identifier>,
) -> LookupCommandBuilder {
    LookupCommandBuilder::table_alias(alias, table_reference)
}

/// Create a LOOKUP command builder with table reference
pub fn lookup_table_reference(table_reference: impl Into<Identifier>) -> LookupCommandBuilder {
    LookupCommandBuilder::table_reference(table_reference)
}

/// Create an EXPLODE command builder
pub fn explode_command() -> ExplodeCommandBuilder<NoClause> {
    ExplodeCommandBuilder::new()
}

/// Create an UNNEST command builder
pub fn unnest_command(expression: impl IntoExpressionBuilder) -> UnnestCommandBuilder {
    UnnestCommandBuilder::new(expression)
}

/// Create a ROWS command builder
pub fn rows_command(expression: impl IntoExpressionBuilder) -> RowsCommandBuilder {
    RowsCommandBuilder::new(expression)
}

/// Create a NEST command builder
pub fn nest_command(identifier: impl Into<Identifier>) -> NestCommandBuilder {
    NestCommandBuilder::new(identifier)
}

/// Create a MATCH command builder
pub fn match_command() -> MatchCommandBuilder {
    MatchCommandBuilder::new()
}
