use std::{
    fmt::{Display, Formatter},
    ops::RangeInclusive,
};

use antlr_rust::parser_rule_context::ParserRuleContext;

use crate::{
    antlr::interval,
    func::def::SpecialPosition,
    sql::expression::{
        literal::{BooleanLiteral, DecimalLiteral, IntegerLiteral, NullLiteral, StringLiteral},
        SQLExpression,
    },
    types::{Type, BOOLEAN, DOUBLE, INT, STRING, UNKNOWN},
};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExpressionTranslation {
    pub sql: SQLExpression,
    pub typ: Type,
    pub span: Option<RangeInclusive<usize>>,
    pub special: Option<SpecialPosition>,
    pub nested_special: Vec<(SpecialPosition, RangeInclusive<usize>)>,
}

impl ExpressionTranslation {
    pub fn with_defaults(typ: Type, sql: SQLExpression) -> Self {
        Self {
            sql,
            typ,
            span: None,
            special: None,
            nested_special: Vec::new(),
        }
    }

    pub fn with_span<'a, T>(mut self, tree: &T) -> Self
    where
        T: ParserRuleContext<'a>,
    {
        self.span = Some(interval(tree));
        self
    }

    pub fn with_special(mut self, position: SpecialPosition) -> Self {
        self.special = Some(position);
        self
    }

    pub fn with_nested_special(
        mut self,
        position: SpecialPosition,
        span: RangeInclusive<usize>,
    ) -> Self {
        self.nested_special.push((position, span));
        self
    }
}

impl Display for ExpressionTranslation {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "Translation yields type:\n{}\n\ninto sql:\n", self.typ,)?;
        self.sql.fmt_indented(f, 4)
    }
}

impl Default for ExpressionTranslation {
    fn default() -> Self {
        Self {
            sql: NullLiteral::default().into(),
            typ: UNKNOWN,
            span: None,
            special: None,
            nested_special: Vec::new(),
        }
    }
}

impl From<crate::tree::ast::expression::Expression> for ExpressionTranslation {
    /// Convert an AST Expression to an ExpressionTranslation.
    /// Only supports literal expressions - will panic for other expression kinds.
    fn from(expr: crate::tree::ast::expression::Expression) -> Self {
        use crate::tree::ast::expression::ExpressionKind;

        match expr.kind {
            ExpressionKind::BooleanLiteral(lit) => {
                Self::with_defaults(BOOLEAN, BooleanLiteral { value: lit.value }.into())
            }
            ExpressionKind::IntLiteral(lit) => {
                Self::with_defaults(INT, IntegerLiteral::from_int(lit.int).into())
            }
            ExpressionKind::StringLiteral(lit) => {
                Self::with_defaults(STRING, StringLiteral::new(&lit.value).into())
            }
            ExpressionKind::NullLiteral(_) => {
                Self::with_defaults(UNKNOWN, NullLiteral::default().into())
            }
            ExpressionKind::DecimalLiteral(lit) => {
                // Convert from unscaled_value/scale representation to string
                let mut s = lit.unscaled_value.to_string();
                let negative = s.starts_with('-');
                if negative {
                    s = s[1..].to_string();
                }
                // Pad with leading zeros if needed
                while s.len() <= lit.scale as usize {
                    s = format!("0{}", s);
                }
                let decimal_pos = s.len() - lit.scale as usize;
                s.insert(decimal_pos, '.');
                if negative {
                    s = format!("-{}", s);
                }
                Self::with_defaults(DOUBLE, DecimalLiteral::new(&s).into())
            }
            _ => panic!(
                "From<Expression> for ExpressionTranslation only supports literals, got: {:?}",
                expr.kind
            ),
        }
    }
}
