//! Decimal formatting via [`fmt::Display`].
use super::U512;
use core::fmt;

/// Formats a [`U512`] as a decimal string.
///
/// Uses repeated division by `10^19` (the largest power of 10 that fits
/// in a `u64`) to extract groups of up to 19 decimal digits at a time,
/// avoiding one-digit-at-a-time division over the full 512-bit width.
/// The value zero formats as `"0"`.
///
/// This is not a hot path. Performs schoolbook long division inline to
/// obtain both quotient and remainder in each iteration.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u512::U512;
///
/// let v = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 42]);
/// assert_eq!(format!("{}", v), "42");
/// assert_eq!(format!("{}", U512::ZERO), "0");
/// ```
impl fmt::Display for U512 {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.is_zero() {
            return f.write_str("0");
        }

        const DIVISOR: u64 = 10_000_000_000_000_000_000; // 10^19
        const GROUP_WIDTH: usize = 19;

        // 2^512 - 1 has 155 decimal digits. 9 groups of 19 covers 171
        // digits (155 needed).
        let mut groups = [0u64; 9];
        let mut count = 0;
        let mut val = *self;

        while !val.is_zero() {
            // Schoolbook division by DIVISOR: iterate 8 limbs from MSB
            // to LSB, carrying the running 128-bit remainder. This
            // produces both quotient limbs and the final remainder.
            let divisor = DIVISOR as u128;
            let mut rem: u128 = 0;
            let mut quotient = [0u64; 8];

            let mut i = 7i32;
            while i >= 0 {
                let cur = (rem << 64) | (val.0[i as usize] as u128);
                quotient[i as usize] = (cur / divisor) as u64;
                rem = cur % divisor;
                i -= 1;
            }

            groups[count] = rem as u64;
            count += 1;
            val = U512(quotient);
        }

        // Write the most significant group without leading zeros
        write!(f, "{}", groups[count - 1])?;

        // Write remaining groups with zero-padding to 19 digits
        for i in (0..count - 1).rev() {
            write!(f, "{:0width$}", groups[i], width = GROUP_WIDTH)?;
        }

        Ok(())
    }
}

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

    /// Zero formats as "0".
    #[test]
    fn zero() {
        assert_eq!(format!("{}", U512::ZERO), "0");
    }

    /// One formats as "1".
    #[test]
    fn one() {
        assert_eq!(format!("{}", U512::ONE), "1");
    }

    /// Small value formats correctly.
    #[test]
    fn small() {
        assert_eq!(
            format!("{}", U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 42])),
            "42",
        );
    }

    /// u64::MAX formats correctly.
    #[test]
    fn u64_max() {
        let v = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, u64::MAX]);
        assert_eq!(format!("{}", v), "18446744073709551615");
    }

    /// Power of 10 formats without spurious digits.
    #[test]
    fn power_of_ten() {
        let v = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 10_000_000_000_000_000_000]);
        assert_eq!(format!("{}", v), "10000000000000000000");
    }

    /// MAX value (2^512 - 1) has 155 decimal digits.
    #[test]
    fn max_value() {
        let s = format!("{}", U512::MAX);
        assert_eq!(
            s,
            "13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095",
        );
    }

    /// Value spanning multiple limbs: 2^64.
    #[test]
    fn multi_limb() {
        let v = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 1, 0]);
        assert_eq!(format!("{}", v), "18446744073709551616");
    }

    /// Value requiring zero-padding between groups.
    #[test]
    fn zero_padding() {
        // 10^19 + 1
        let v = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 10_000_000_000_000_000_000]);
        let v = v + U512::ONE;
        assert_eq!(format!("{}", v), "10000000000000000001");
    }
}
