//! Schoolbook division of a [`U384`] by a single `u64` divisor.
use super::U384;

impl U384 {
    /// Divides `self` by a single `u64` divisor in-place using schoolbook
    /// long division, replacing `self` with the quotient and returning the
    /// remainder.
    ///
    /// Processes limbs from most significant to least significant,
    /// carrying the remainder forward via 128-bit intermediate division.
    ///
    /// # Panics
    ///
    /// Panics if `d` is zero (division by zero).
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u384::U384;
    ///
    /// let mut v = U384::from_be_limbs([0, 0, 0, 0, 0, 100]);
    /// let rem = v.div_u64(7);
    /// assert_eq!(v, U384::from_be_limbs([0, 0, 0, 0, 0, 14]));
    /// assert_eq!(rem, 2);
    /// ```
    #[inline]
    pub fn div_u64(&mut self, d: u64) -> u64 {
        let d128 = d as u128;
        let mut rem: u128 = 0;
        let mut i = 5;
        loop {
            let cur = (rem << 64) | (self.0[i] as u128);
            self.0[i] = (cur / d128) as u64;
            rem = cur % d128;
            if i == 0 {
                break;
            }
            i -= 1;
        }
        rem as u64
    }
}

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

    /// 100 / 7 = 14 remainder 2.
    #[test]
    fn basic() {
        let mut v = U384::from_be_limbs([0, 0, 0, 0, 0, 100]);
        let rem = v.div_u64(7);
        assert_eq!(v, U384::from_be_limbs([0, 0, 0, 0, 0, 14]));
        assert_eq!(rem, 2);
    }

    /// Division by 1 returns the value unchanged with remainder 0.
    #[test]
    fn div_by_one() {
        let mut v = U384::from_be_limbs([1, 2, 3, 4, 5, 6]);
        let rem = v.div_u64(1);
        assert_eq!(v, U384::from_be_limbs([1, 2, 3, 4, 5, 6]));
        assert_eq!(rem, 0);
    }

    /// Dividing zero by anything yields zero with remainder 0.
    #[test]
    fn zero_dividend() {
        let mut v = U384::ZERO;
        let rem = v.div_u64(42);
        assert_eq!(v, U384::ZERO);
        assert_eq!(rem, 0);
    }

    /// Division of a multi-limb value.
    #[test]
    fn multi_limb() {
        // 2^64 / 3 = 6148914691236517205, remainder 1
        let mut v = U384::from_be_limbs([0, 0, 0, 0, 1, 0]);
        let rem = v.div_u64(3);
        assert_eq!(v, U384::from_be_limbs([0, 0, 0, 0, 0, 6148914691236517205]));
        assert_eq!(rem, 1);
    }

    /// Dividing by u64::MAX.
    #[test]
    fn div_by_max() {
        let mut v = U384::from_be_limbs([0, 0, 0, 0, 0, u64::MAX]);
        let rem = v.div_u64(u64::MAX);
        assert_eq!(v, U384::from_be_limbs([0, 0, 0, 0, 0, 1]));
        assert_eq!(rem, 0);
    }

    /// Quotient times divisor plus remainder equals original.
    #[test]
    fn round_trip() {
        let original = U384::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1111, 0x2222]);
        let mut v = original;
        let d: u64 = 1_000_000_007;
        let rem = v.div_u64(d);

        // v * d + rem should equal original
        // Verify by checking: original - rem should be divisible by d
        let mut check = original - U384::from_be_limbs([0, 0, 0, 0, 0, rem]);
        let check_rem = check.div_u64(d);
        assert_eq!(check_rem, 0);
        assert_eq!(check, v);
    }

    /// Division by zero panics.
    #[test]
    #[should_panic]
    fn div_by_zero() {
        let mut v = U384::ONE;
        v.div_u64(0);
    }
}
