//! Constructs a [`KnuthD`] by normalizing the divisor and precomputing the MG10 reciprocal.
use super::KnuthD;

impl KnuthD {
    /// Creates a new [`KnuthD`] for the given little-endian divisor with `n`
    /// significant limbs.
    ///
    /// Normalizes the divisor by left-shifting so the leading limb's MSB is
    /// set, then precomputes the MG10 reciprocal for the top two normalized
    /// limbs. The normalization shift amount is stored for later use when
    /// unnormalizing the remainder.
    ///
    /// # Panics
    ///
    /// Panics if `n < 2` (single-digit division should use
    /// [`U512::div_u64`](crate::u512::U512::div_u64) instead).
    pub(crate) fn new(divisor_le: &[u64; 4], n: usize) -> Self {
        debug_assert!(n >= 2, "KnuthD requires n >= 2");

        let s = divisor_le[n - 1].leading_zeros();
        let mut vn = [0u64; 4];

        if s > 0 {
            for i in (1..n).rev() {
                vn[i] = (divisor_le[i] << s) | (divisor_le[i - 1] >> (64 - s));
            }
            vn[0] = divisor_le[0] << s;
        } else {
            vn[..n].copy_from_slice(&divisor_le[..n]);
        }

        let d1 = vn[n - 1];
        let d0 = vn[n - 2];
        let d = ((d1 as u128) << 64) | (d0 as u128);

        let mut kd = Self {
            vn,
            d1,
            d0,
            d,
            v: 0,
            n,
            s,
        };
        kd.v = kd.reciprocal_2();
        kd
    }
}

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

    /// Constructor normalizes a 2-limb divisor correctly.
    #[test]
    fn new_two_limb() {
        let kd = KnuthD::new(&[1, 1, 0, 0], 2);
        assert_eq!(kd.n, 2);
        // vn[1] should have MSB set after normalization
        assert!(kd.d1 >= 1u64 << 63);
    }

    /// Constructor with already-normalized divisor uses shift 0.
    #[test]
    fn new_already_normalized() {
        let kd = KnuthD::new(&[0, 1u64 << 63, 0, 0], 2);
        assert_eq!(kd.s, 0);
        assert_eq!(kd.d1, 1u64 << 63);
    }

    /// Constructor with 4-limb divisor.
    #[test]
    fn new_four_limb() {
        let kd = KnuthD::new(&[1, 2, 3, 4], 4);
        assert_eq!(kd.n, 4);
        assert!(kd.d1 >= 1u64 << 63);
    }

    /// Reciprocal is non-zero after construction.
    #[test]
    fn reciprocal_computed() {
        let kd = KnuthD::new(&[1, 1, 0, 0], 2);
        assert_ne!(kd.v, 0);
    }
}
