//! Operator expression builders

use std::rc::Rc;

use crate::tree::ast::expression::{
    BinaryOperator, Expression, UnaryPostfixOperator, UnaryPrefixOperator,
};
use crate::tree::ast::node::Span;
use crate::tree::ast::ops::{BinaryOp, UnaryPostfixOp, UnaryPrefixOp};
use crate::tree::builder::null;

use super::{ExpressionBuilder, IntoExpressionBuilder};

/// Builder for binary operators
#[derive(Debug)]
pub struct BinaryOperatorBuilder {
    operator: BinaryOp,
    left: Box<dyn ExpressionBuilder>,
    right: Box<dyn ExpressionBuilder>,
}

impl BinaryOperatorBuilder {
    pub fn new(
        operator: impl Into<BinaryOp>,
        left: impl IntoExpressionBuilder,
        right: impl IntoExpressionBuilder,
    ) -> Self {
        Self {
            operator: operator.into(),
            left: left.into_expression_builder(),
            right: right.into_expression_builder(),
        }
    }
}

impl ExpressionBuilder for BinaryOperatorBuilder {
    fn build(&self) -> Expression {
        Expression {
            span: Span::NONE,
            kind: BinaryOperator {
                operator: self.operator.clone(),
                left: Rc::new(self.left.build()),
                right: Rc::new(self.right.build()),
            }
            .into(),
        }
    }
}

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

/// Builder for unary prefix operators
#[derive(Debug)]
pub struct UnaryPrefixOperatorBuilder {
    operator: UnaryPrefixOp,
    operand: Box<dyn ExpressionBuilder>,
}

impl UnaryPrefixOperatorBuilder {
    pub fn new(operator: impl Into<UnaryPrefixOp>, operand: impl IntoExpressionBuilder) -> Self {
        Self {
            operator: operator.into(),
            operand: operand.into_expression_builder(),
        }
    }
}

impl ExpressionBuilder for UnaryPrefixOperatorBuilder {
    fn build(&self) -> Expression {
        Expression {
            span: Span::NONE,
            kind: UnaryPrefixOperator {
                operator: self.operator.clone(),
                operand: Rc::new(self.operand.build()),
            }
            .into(),
        }
    }
}

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

/// Builder for unary postfix operators
#[derive(Debug)]
pub struct UnaryPostfixOperatorBuilder {
    operator: UnaryPostfixOp,
    operand: Box<dyn ExpressionBuilder>,
}

impl UnaryPostfixOperatorBuilder {
    pub fn new(operator: impl Into<UnaryPostfixOp>, operand: impl IntoExpressionBuilder) -> Self {
        Self {
            operator: operator.into(),
            operand: operand.into_expression_builder(),
        }
    }
}

impl ExpressionBuilder for UnaryPostfixOperatorBuilder {
    fn build(&self) -> Expression {
        Expression {
            span: Span::NONE,
            kind: UnaryPostfixOperator {
                operator: self.operator.clone(),
                operand: Rc::new(self.operand.build()),
            }
            .into(),
        }
    }
}

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

// Convenience functions for common operators

/// Addition operator
pub fn add(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Add, left, right)
}

/// Subtraction operator
pub fn subtract(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Subtract, left, right)
}

/// Multiplication operator
pub fn multiply(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Multiply, left, right)
}

/// Division operator
pub fn divide(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Divide, left, right)
}

/// Modulo operator
pub fn modulo(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Modulo, left, right)
}

/// Equality operator
pub fn eq(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Equal, left, right)
}

/// Inequality operator
pub fn ne(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::NotEqual, left, right)
}

/// Less than operator
pub fn lt(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::LessThan, left, right)
}

/// Less than or equal operator
pub fn lte(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::LessThanOrEqual, left, right)
}

/// Greater than operator
pub fn gt(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::GreaterThan, left, right)
}

/// Greater than or equal operator
pub fn gte(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::GreaterThanOrEqual, left, right)
}

/// Logical AND operator
pub fn and(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::And, left, right)
}

/// Logical OR operator
pub fn or(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Or, left, right)
}

/// Unary negation operator
pub fn negate(operand: impl IntoExpressionBuilder) -> UnaryPrefixOperatorBuilder {
    UnaryPrefixOperatorBuilder::new(UnaryPrefixOp::Minus, operand)
}

/// Unary NOT operator
pub fn not(operand: impl IntoExpressionBuilder) -> UnaryPrefixOperatorBuilder {
    UnaryPrefixOperatorBuilder::new(UnaryPrefixOp::Not, operand)
}

/// IS NULL operator (binary operator with null literal)
pub fn is_null(operand: impl IntoExpressionBuilder) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::Is, operand, null())
}

/// IS NOT NULL operator (binary operator with null literal)
pub fn is_not_null(operand: impl IntoExpressionBuilder) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::IsNot, operand, null())
}

/// IN operator
pub fn in_(
    left: impl IntoExpressionBuilder,
    right: impl IntoExpressionBuilder,
) -> BinaryOperatorBuilder {
    BinaryOperatorBuilder::new(BinaryOp::In, left, right)
}
