/// Evaluate a simple arithmetic expression containing +, -, *, /.
/// Supports decimal numbers. Returns None if the input is not a valid expression.
pub fn eval_expr(input: &str) -> Option<f64> {
    let input = input.trim();
    if input.is_empty() {
        return None;
    }

    // If it's just a plain number, parse directly
    if let Ok(v) = input.parse::<f64>() {
        return Some(v);
    }

    // Tokenize
    let mut tokens = Vec::new();
    let mut num_buf = String::new();

    for ch in input.chars() {
        if ch.is_ascii_digit() || ch == '.' {
            num_buf.push(ch);
        } else if ch == '+' || ch == '-' || ch == '*' || ch == '/' {
            if num_buf.is_empty() {
                return None;
            }
            tokens.push(Token::Num(num_buf.parse::<f64>().ok()?));
            num_buf.clear();
            tokens.push(Token::Op(ch));
        } else if ch.is_whitespace() {
            continue;
        } else {
            return None;
        }
    }
    if !num_buf.is_empty() {
        tokens.push(Token::Num(num_buf.parse::<f64>().ok()?));
    }
    if tokens.is_empty() {
        return None;
    }

    // Evaluate: * and / first (left to right), then + and -
    let mut simplified: Vec<Token> = Vec::new();
    let mut i = 0;
    while i < tokens.len() {
        if !simplified.is_empty() {
            match simplified.last() {
                Some(Token::Op('*')) | Some(Token::Op('/')) => {
                    if let Token::Num(b) = &tokens[i] {
                        let op = if let Some(Token::Op(op)) = simplified.pop() { op } else { return None; };
                        if let Some(Token::Num(a)) = simplified.pop() {
                            let result = if op == '*' { a * b } else {
                                if *b == 0.0 { return None; }
                                a / b
                            };
                            simplified.push(Token::Num(result));
                            i += 1;
                            continue;
                        }
                        return None;
                    }
                }
                _ => {}
            }
        }
        simplified.push(tokens[i].clone());
        i += 1;
    }

    // Second pass: handle + and -
    let mut result = match simplified.first()? {
        Token::Num(n) => *n,
        _ => return None,
    };

    let mut j = 1;
    while j + 1 < simplified.len() {
        let num = match &simplified[j + 1] {
            Token::Num(n) => *n,
            _ => return None,
        };
        match &simplified[j] {
            Token::Op('+') => result += num,
            Token::Op('-') => result -= num,
            _ => return None,
        }
        j += 2;
    }

    Some(result)
}

#[derive(Clone, Debug)]
enum Token {
    Num(f64),
    Op(char),
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_plain_number() {
        assert_eq!(eval_expr("12.50"), Some(12.50));
    }

    #[test]
    fn test_addition() {
        assert_eq!(eval_expr("12.50+8.75"), Some(21.25));
    }

    #[test]
    fn test_subtraction() {
        assert_eq!(eval_expr("100-25.50"), Some(74.50));
    }

    #[test]
    fn test_multiplication() {
        assert_eq!(eval_expr("3*4.5"), Some(13.5));
    }

    #[test]
    fn test_mul_before_add() {
        assert_eq!(eval_expr("10+5*2"), Some(20.0));
    }

    #[test]
    fn test_spaces() {
        assert_eq!(eval_expr("10 + 5"), Some(15.0));
    }

    #[test]
    fn test_empty() {
        assert_eq!(eval_expr(""), None);
    }

    #[test]
    fn test_invalid() {
        assert_eq!(eval_expr("abc"), None);
    }

    #[test]
    fn test_chain() {
        assert_eq!(eval_expr("1+2+3"), Some(6.0));
    }

    #[test]
    fn test_mixed_ops() {
        // 5 + 3*2 - 1 = 5 + 6 - 1 = 10
        assert_eq!(eval_expr("5+3*2-1"), Some(10.0));
    }

    #[test]
    fn test_division() {
        assert_eq!(eval_expr("10/4"), Some(2.5));
    }

    #[test]
    fn test_division_by_zero() {
        assert_eq!(eval_expr("10/0"), None);
    }

    #[test]
    fn test_div_before_add() {
        // 10 + 6/2 = 10 + 3 = 13
        assert_eq!(eval_expr("10+6/2"), Some(13.0));
    }
}
