//! Two's complement negation wrapping at 2^256.

use super::U256;

impl U256 {
    /// Computes the two's complement negation `2^256 - self`, wrapping on
    /// overflow (i.e., negating zero returns zero).
    ///
    /// This is equivalent to `(!self).overflowing_add(&ONE).0` but computed
    /// via `ZERO.overflowing_sub(self)` for clarity.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// let p = U256::from_be_limbs([
    ///     0xFFFFFFFFFFFFFFFF,
    ///     0xFFFFFFFFFFFFFFFF,
    ///     0xFFFFFFFFFFFFFFFF,
    ///     0xFFFFFFFEFFFFFC2F,
    /// ]);
    /// let complement = p.negate();
    /// assert_eq!(complement, U256::from_be_limbs([0, 0, 0, 0x1000003D1]));
    /// ```
    #[inline]
    pub const fn negate(&self) -> U256 {
        U256::ZERO.overflowing_sub(self).0
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;
    /// Negating zero returns zero.
    #[test]
    fn neg_zero() {
        assert_eq!(U256::ZERO.negate(), U256::ZERO);
    }

    /// Negating one returns 2^256 - 1 (all bits set).
    #[test]
    fn neg_one() {
        assert_eq!(
            U256::ONE.negate(),
            U256::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
        );
    }

    /// Double negation is identity.
    #[test]
    fn double_neg() {
        let a = U256::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0]);
        assert_eq!(a.negate().negate(), a);
    }

    /// Negation of secp256k1 P equals P_COMPLEMENT.
    #[test]
    fn neg_p() {
        let p = U256::from_be_limbs([
            0xFFFFFFFF_FFFFFFFF,
            0xFFFFFFFF_FFFFFFFF,
            0xFFFFFFFF_FFFFFFFF,
            0xFFFFFFFE_FFFFFC2F,
        ]);
        let p_complement = U256::from_be_limbs([0, 0, 0, 0x1000003D1]);
        assert_eq!(p.negate(), p_complement);
    }

    /// x + (-x) wraps to zero.
    #[test]
    fn add_neg_is_zero() {
        let a = U256::from_be_limbs([0xAB, 0xCD, 0xEF, 0x42]);
        let (sum, _) = a.overflowing_add(&a.negate());
        assert_eq!(sum, U256::ZERO);
    }
}
