pub fn format_number(n: f64, decimals: usize, sep: char) -> String {
    let s = format!("{:.*}", decimals, n);
    let parts: Vec<&str> = s.split('.').collect();
    let int_part = parts[0];
    let mut out = String::new();
    for (count, c) in int_part.chars().rev().enumerate() {
        if count > 0 && count % 3 == 0 {
            out.insert(0, sep);
        }
        out.insert(0, c);
    }
    if parts.len() > 1 {
        out.push('.');
        out.push_str(parts[1]);
    }
    out
}

pub fn format_currency(amount: f64, currency: &str) -> String {
    format!("{:.2}{}", amount, currency)
}

pub fn format_percentage(ratio: f64, _decimals: usize) -> String {
    format!("{:.2}%", ratio * 100.0)
}

pub fn round(n: f64, decimals: u32) -> f64 {
    let m = 10f64.powi(decimals as i32);
    (n * m).round() / m
}

pub fn ceil(n: f64, decimals: u32) -> f64 {
    let m = 10f64.powi(decimals as i32);
    (n * m).ceil() / m
}

pub fn floor(n: f64, decimals: u32) -> f64 {
    let m = 10f64.powi(decimals as i32);
    (n * m).floor() / m
}

pub fn clamp(n: f64, min: f64, max: f64) -> f64 {
    if n < min {
        min
    } else if n > max {
        max
    } else {
        n
    }
}

pub fn lerp(a: f64, b: f64, t: f64) -> f64 {
    a + (b - a) * t
}

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

    #[test]
    fn test_format_number() {
        assert_eq!(format_number(1234.567, 2, ','), "1,234.57");
    }

    #[test]
    fn test_round_ceiling_floor() {
        assert_eq!(round(1.234, 2), 1.23);
        assert_eq!(ceil(1.234, 2), 1.24);
        assert_eq!(floor(1.234, 2), 1.23);
    }

    #[test]
    fn test_clamp() {
        assert_eq!(clamp(5.0, 0.0, 10.0), 5.0);
        assert_eq!(clamp(-1.0, 0.0, 10.0), 0.0);
        assert_eq!(clamp(15.0, 0.0, 10.0), 10.0);
    }

    #[test]
    fn test_lerp() {
        assert_eq!(lerp(0.0, 10.0, 0.5), 5.0);
    }
}
