//! Expression builder system for constructing AST and TypedAST nodes
//!
//! This module provides a fluent API for building expression trees without
//! duplicating type checking or validation logic. All intelligence is delegated
//! to the existing `TypedExpression::from_ast_with_context` implementation.

use crate::tree::{
    ast::{expression::Expression, identifier::Identifier},
    typed_ast::expression::TypedExpression,
};

mod access;
mod collections;
mod functions;
mod lambda;
mod literal;
mod operators;
mod special;

// Command, Pipeline, Query, and Identifier builders
pub mod command;
pub mod identifier;
pub mod pipeline;
pub mod query;

// Re-export commonly used builders
pub use command::{
    agg_command, append_command, distinct_command, drop_command, explode_command, from_command,
    join_table_alias, join_table_reference, limit_command, lookup_table_alias,
    lookup_table_reference, match_command, nest_command, parse_command, pattern_quantified,
    pattern_with_alias, pattern_with_alias_and_quantifier, quantifier_any_number,
    quantifier_at_least_one, quantifier_exactly, quantifier_zero_or_one, rows_command,
    select_command, set_command, sort_command, table_ref, union_command, unnest_command,
    where_command, window_command, within_command, AggCommandBuilder, AppendCommandBuilder,
    DistinctCommandBuilder, DropCommandBuilder, ExplodeCommandBuilder, FromCommandBuilder,
    JoinCommandBuilder, LimitCommandBuilder, LookupCommandBuilder, MatchCommandBuilder,
    NestCommandBuilder, NoClause, ParseCommandBuilder, ParseCommandBuilderWithPattern,
    RowsCommandBuilder, SelectCommandBuilder, SetCommandBuilder, SortCommandBuilder,
    UnionCommandBuilder, UnnestCommandBuilder, ValidParseCommandBuilder, WhereCommandBuilder,
    WindowCommandBuilder, WithClause, WithinCommandBuilder,
};
pub use identifier::{ident, IdentifierBuilder};
pub use pipeline::{pipeline, pipeline_from_expression, PipelineBuilder};
pub use query::{query, IntoPipelineRc, QueryBuilder, QueryBuilderWithMain};

pub use access::{
    // Convenience functions
    field,
    index,
    // Builders
    FieldLookupBuilder,
    IndexAccessBuilder,
};
pub use collections::{
    // Convenience functions
    array,
    pair,
    struct_literal,
    tuple,
    // Builders
    ArrayLiteralBuilder,
    PairLiteralBuilder,
    StructLiteralBuilder,
    TupleLiteralBuilder,
};
pub use functions::{
    // Convenience functions
    call,
    FunctionCallBuilder,
};
pub use lambda::{lambda, lambda1, lambda2, LambdaBuilder, LambdaBuilderWithBody};
pub use literal::{
    BoolLiteralBuilder, DecimalLiteralBuilder, DoubleLiteralBuilder, IntLiteralBuilder,
    IntervalLiteralBuilder, NullLiteralBuilder, StringLiteralBuilder,
};
pub use operators::{
    // Convenience functions
    add,
    and,
    divide,
    eq,
    gt,
    gte,
    in_,
    is_not_null,
    is_null,
    lt,
    lte,
    modulo,
    multiply,
    ne,
    negate,
    not,
    not_in,
    or,
    subtract,
    BinaryOperatorBuilder,
    UnaryPostfixOperatorBuilder,
    UnaryPrefixOperatorBuilder,
};
pub use special::{
    at,
    at_day,
    at_hour,
    at_minute,
    at_month,
    at_second,
    at_week,
    at_year,
    // Convenience functions
    cast,
    error,
    field_ref,
    // Builders
    CastBuilder,
    ErrorBuilder,
    FieldReferenceBuilder,
    TsTruncBuilder,
};

/// Builder for configuring expression translation options with fluent API
///
/// This stores the AST and allows customizing the context used for type checking.
/// The builder is consumed when `.build()` or `.build_with_errors()` is called.
///
/// Core trait for all expression builders
pub trait ExpressionBuilder: std::fmt::Debug {
    /// Build an untyped AST Expression
    fn build(&self) -> Expression;
}

/// Trait for types that can be converted into expression builders
pub trait IntoExpressionBuilder {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder>;
}

// Implement IntoExpressionBuilder for primitives
impl IntoExpressionBuilder for i64 {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(IntLiteralBuilder::new(self))
    }
}

impl IntoExpressionBuilder for i32 {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(IntLiteralBuilder::new(self as i64))
    }
}

impl IntoExpressionBuilder for f64 {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(DoubleLiteralBuilder::new(self))
    }
}

impl IntoExpressionBuilder for f32 {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(DoubleLiteralBuilder::new(self as f64))
    }
}

impl IntoExpressionBuilder for &str {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(StringLiteralBuilder::new(self))
    }
}

impl IntoExpressionBuilder for String {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(StringLiteralBuilder::new(self))
    }
}

impl IntoExpressionBuilder for bool {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(BoolLiteralBuilder::new(self))
    }
}

// Implement IntoExpressionBuilder for Rust range types
// This allows writing `days(1)..days(7)` directly
use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
use std::sync::Arc;

impl<T> IntoExpressionBuilder for Range<T>
where
    T: ExpressionBuilder + IntoExpressionBuilder,
{
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        use crate::tree::ast::ops::BinaryOp;
        Box::new(BinaryOperatorBuilder::new(
            BinaryOp::Range,
            self.start,
            self.end,
        ))
    }
}

impl<T> IntoExpressionBuilder for RangeFrom<T>
where
    T: ExpressionBuilder + IntoExpressionBuilder,
{
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        use crate::tree::ast::ops::BinaryOp;
        // `start..` becomes `start..NULL`
        Box::new(BinaryOperatorBuilder::new(
            BinaryOp::Range,
            self.start,
            null(),
        ))
    }
}

impl<T> IntoExpressionBuilder for RangeInclusive<T>
where
    T: ExpressionBuilder + IntoExpressionBuilder,
{
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        use crate::tree::ast::ops::BinaryOp;
        let (start, end) = self.into_inner();
        Box::new(BinaryOperatorBuilder::new(
            BinaryOp::RangeInclusive,
            start,
            end,
        ))
    }
}

impl<T> IntoExpressionBuilder for RangeToInclusive<T>
where
    T: ExpressionBuilder + IntoExpressionBuilder,
{
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        use crate::tree::ast::ops::BinaryOp;
        // `..=end` becomes `NULL..=end`
        Box::new(BinaryOperatorBuilder::new(
            BinaryOp::RangeInclusive,
            null(),
            self.end,
        ))
    }
}

impl<T> IntoExpressionBuilder for RangeTo<T>
where
    T: ExpressionBuilder + IntoExpressionBuilder,
{
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        use crate::tree::ast::ops::BinaryOp;
        // `..end` becomes `NULL..end`
        Box::new(BinaryOperatorBuilder::new(
            BinaryOp::Range,
            null(),
            self.end,
        ))
    }
}

impl IntoExpressionBuilder for RangeFull {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        use crate::tree::ast::expression::UnboundRangeLiteral;
        use crate::tree::ast::node::Span;
        // `..` becomes UnboundRangeLiteral
        Box::new(ExpressionWrapper(Expression {
            span: Span::NONE,
            kind: UnboundRangeLiteral.into(),
        }))
    }
}

// Implement IntoExpressionBuilder for Box<dyn ExpressionBuilder>
impl IntoExpressionBuilder for Box<dyn ExpressionBuilder> {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        self
    }
}

// Implement IntoExpressionBuilder for specific builder types
// We can't do a blanket impl because it conflicts with other impls

// Implement IntoExpressionBuilder for existing Expression
impl IntoExpressionBuilder for Expression {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(ExpressionWrapper(self))
    }
}

// Implement IntoExpressionBuilder for Arc<Expression>
impl IntoExpressionBuilder for Arc<Expression> {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        Box::new(ExpressionWrapper((*self).clone()))
    }
}

// Implement IntoExpressionBuilder for existing TypedExpression
impl IntoExpressionBuilder for TypedExpression {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        // Extract the AST from the typed expression
        Box::new(ExpressionWrapper((*self.ast).clone()))
    }
}

// Implement IntoExpressionBuilder for tree Identifier
impl IntoExpressionBuilder for Identifier {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        match self {
            // Simple identifier -> field reference
            Identifier::Simple(simple) => Box::new(field_ref(simple.as_str())),
            // Compound identifier -> nested field access (e.g., a.b.c -> field(field(field_ref("a"), "b"), "c"))
            Identifier::Compound(compound) => {
                // Start with the first part as a field reference
                let mut result: Box<dyn ExpressionBuilder> =
                    Box::new(field_ref(compound.first().as_str()));

                // Chain field accesses for the remaining parts
                for part in compound.rest_parts() {
                    result = Box::new(field(result, part.as_str()));
                }

                result
            }
        }
    }
}

// Also support &Identifier for convenience
impl IntoExpressionBuilder for &Identifier {
    fn into_expression_builder(self) -> Box<dyn ExpressionBuilder> {
        self.clone().into_expression_builder()
    }
}

// Wrapper for existing Expression to implement ExpressionBuilder
#[derive(Debug)]
struct ExpressionWrapper(Expression);

impl ExpressionBuilder for ExpressionWrapper {
    fn build(&self) -> Expression {
        self.0.clone()
    }
}

// Convenience functions for creating builders

/// Create an integer literal
pub fn int(value: i64) -> IntLiteralBuilder {
    IntLiteralBuilder::new(value)
}

/// Create a double literal
pub fn double(value: f64) -> DoubleLiteralBuilder {
    DoubleLiteralBuilder::new(value)
}

/// Create a string literal
pub fn string(value: impl Into<String>) -> StringLiteralBuilder {
    StringLiteralBuilder::new(value)
}

/// Create a boolean literal
pub fn boolean(value: bool) -> BoolLiteralBuilder {
    BoolLiteralBuilder::new(value)
}

/// Create a null literal
pub fn null() -> NullLiteralBuilder {
    NullLiteralBuilder::new()
}

/// Create a decimal literal from string representation like "3.14"
pub fn decimal(value: &str) -> Result<DecimalLiteralBuilder, String> {
    DecimalLiteralBuilder::from_string(value)
}

/// Create a decimal literal from components
pub fn decimal_from_parts(
    unscaled_value: i128,
    precision: u32,
    scale: u32,
) -> DecimalLiteralBuilder {
    DecimalLiteralBuilder::new(unscaled_value, precision, scale)
}

// Interval literal convenience functions
use crate::tree::ast::expression::IntervalUnit;

/// Create an interval literal builder
pub fn interval(value: i64, unit: IntervalUnit) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, unit)
}

/// Create a millisecond interval
pub fn milliseconds(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Millisecond)
}

/// Create a second interval
pub fn seconds(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Second)
}

/// Create a minute interval
pub fn minutes(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Minute)
}

/// Create an hour interval
pub fn hours(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Hour)
}

/// Create a day interval
pub fn days(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Day)
}

/// Create a week interval
pub fn weeks(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Week)
}

/// Create a month interval
pub fn months(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Month)
}

/// Create a quarter interval
pub fn quarters(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Quarter)
}

/// Create a year interval
pub fn years(value: i64) -> IntervalLiteralBuilder {
    IntervalLiteralBuilder::new(value, IntervalUnit::Year)
}

#[cfg(test)]
mod tests;
