use hamelin_lib::sql::expression::identifier::SimpleIdentifier;
use hamelin_lib::sql::expression::literal::{NullLiteral, RowLiteral};
use hamelin_lib::sql::expression::Cast;
use hamelin_lib::sql::expression::{Leaf, SQLExpression};
use hamelin_lib::sql::types::{SQLBaseType, SQLRowType, SQLType};

#[derive(Debug, Clone)]
pub struct RangeBuilder {
    pub begin: SQLExpression,
    pub begin_type: Option<SQLType>,
    pub end: SQLExpression,
    pub end_type: Option<SQLType>,
    pub end_inclusive: bool,
}

impl Default for RangeBuilder {
    fn default() -> Self {
        RangeBuilder {
            begin: SQLExpression::Leaf(Leaf::NullLiteral(NullLiteral::default())),
            begin_type: None,
            end: SQLExpression::Leaf(Leaf::NullLiteral(NullLiteral::default())),
            end_type: None,
            end_inclusive: false,
        }
    }
}

impl RangeBuilder {
    pub fn from_literal(expression: SQLExpression) -> Option<RangeBuilder> {
        if let SQLExpression::Cast(cast) = expression {
            if let SQLExpression::RowLiteral(row) = *cast.expression {
                if let SQLType::SQLRowType(cast_type) = cast.to {
                    let mut rb = RangeBuilder::default();

                    if let Some(begin) = row.values.get(0) {
                        if let SQLExpression::Leaf(Leaf::NullLiteral(_)) = begin {
                        } else {
                            rb = rb.with_begin(
                                begin.clone(),
                                cast_type.bindings[&SimpleIdentifier::new("begin")].clone(),
                            );
                        }
                    }

                    if let Some(end) = row.values.get(1) {
                        if let SQLExpression::Leaf(Leaf::NullLiteral(_)) = end {
                        } else {
                            rb = rb.with_end(
                                end.clone(),
                                cast_type.bindings[&SimpleIdentifier::new("end")].clone(),
                            );
                        }
                    }

                    return Some(rb);
                }
            }
        }

        None
    }

    pub fn with_begin(self, begin: SQLExpression, begin_type: SQLType) -> RangeBuilder {
        RangeBuilder {
            begin,
            begin_type: Some(begin_type.clone()),
            end: self.end,
            end_type: self.end_type.or(Some(begin_type)),
            end_inclusive: self.end_inclusive,
        }
    }

    pub fn with_end(self, end: SQLExpression, end_type: SQLType) -> RangeBuilder {
        RangeBuilder {
            begin: self.begin,
            begin_type: self.begin_type.or(Some(end_type.clone())),
            end,
            end_type: Some(end_type),
            end_inclusive: self.end_inclusive,
        }
    }

    pub fn with_end_inclusive(self) -> RangeBuilder {
        RangeBuilder {
            end_inclusive: true,
            ..self
        }
    }

    pub fn build(self) -> SQLExpression {
        let begin_type = self.begin_type.unwrap_or(SQLBaseType::Unknown.into());
        let end_type = self.end_type.unwrap_or(SQLBaseType::Unknown.into());

        Cast::new(
            RowLiteral::new(vec![self.begin, self.end]).into(),
            SQLRowType::default()
                .with_str("begin", begin_type)
                .with_str("end", end_type)
                .into(),
        )
        .into()
    }
}
