//! Integer remainder via the [`Rem`] trait.

use super::U256;
use core::ops::Rem;

/// Integer remainder of two 256-bit unsigned integers.
///
/// Returns `self % rhs` (the remainder after integer division). Delegates
/// to [`U256::div_rem`] and returns only the remainder.
///
/// # Panics
///
/// Loops indefinitely if `rhs` is zero.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u256::U256;
///
/// let a = U256::from_be_limbs([0, 0, 0, 10]);
/// let b = U256::from_be_limbs([0, 0, 0, 3]);
/// assert_eq!(a % b, U256::from_be_limbs([0, 0, 0, 1]));
/// ```
impl Rem for U256 {
    type Output = U256;

    #[inline]
    fn rem(self, rhs: U256) -> U256 {
        self.div_rem(&rhs).1
    }
}

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

    /// 10 % 3 = 1.
    #[test]
    fn ten_mod_three() {
        let a = U256::from_be_limbs([0, 0, 0, 10]);
        let b = U256::from_be_limbs([0, 0, 0, 3]);
        assert_eq!(a % b, U256::from_be_limbs([0, 0, 0, 1]));
    }

    /// 8 % 2 = 0 (exact division).
    #[test]
    fn exact_division() {
        let a = U256::from_be_limbs([0, 0, 0, 8]);
        let b = U256::from_be_limbs([0, 0, 0, 2]);
        assert_eq!(a % b, U256::ZERO);
    }

    /// Remainder by one is always zero.
    #[test]
    fn mod_by_one() {
        let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
        assert_eq!(a % U256::ONE, U256::ZERO);
    }

    /// Self mod self is zero.
    #[test]
    fn self_mod() {
        let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
        assert_eq!(a % a, U256::ZERO);
    }

    /// Dividend smaller than divisor yields the dividend.
    #[test]
    fn smaller_dividend() {
        let a = U256::from_be_limbs([0, 0, 0, 3]);
        let b = U256::from_be_limbs([0, 0, 0, 10]);
        assert_eq!(a % b, a);
    }

    /// MAX % 2 = 1 (MAX is odd).
    #[test]
    fn max_mod_two() {
        let two = U256::from_be_limbs([0, 0, 0, 2]);
        assert_eq!(U256::MAX % two, U256::ONE);
    }

    /// Consistency: (a / b) * b + (a % b) == a.
    #[test]
    fn div_rem_consistency() {
        let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
        let b = U256::from_be_limbs([0, 0, 0x1111, 0x2222]);
        let q = a / b;
        let r = a % b;
        assert_eq!(q.mul_mod(&b, &U256::MAX) + r, a);
    }
}
