//! F0 — Arithmetic monomers: MC_00–MC_07
//!
//! All arithmetic is bounded. No operation can produce undefined behavior,
//! integer overflow, or panic on any valid input.

/// MC_00 — ADD8: 8-bit wrapping addition.
///
/// Returns `a + b` with wrapping on overflow (modular arithmetic).
///
/// ```
/// use brik64_core::mc::add8;
/// assert_eq!(add8(200, 100), 44); // wraps: (200+100) % 256
/// assert_eq!(add8(10, 20), 30);
/// ```
pub fn add8(a: u8, b: u8) -> u8 {
    a.wrapping_add(b)
}

/// MC_01 — SUB8: 8-bit wrapping subtraction.
///
/// Returns `a - b` with wrapping on underflow (modular arithmetic).
///
/// ```
/// use brik64_core::mc::sub8;
/// assert_eq!(sub8(5, 10), 251);  // wraps
/// assert_eq!(sub8(20, 5), 15);
/// ```
pub fn sub8(a: u8, b: u8) -> u8 {
    a.wrapping_sub(b)
}

/// MC_02 — MUL8: 8-bit wrapping multiplication.
///
/// Returns `a * b` with wrapping on overflow (modular arithmetic).
///
/// ```
/// use brik64_core::mc::mul8;
/// assert_eq!(mul8(20, 20), 144); // wraps: (400) % 256
/// assert_eq!(mul8(3, 4), 12);
/// ```
pub fn mul8(a: u8, b: u8) -> u8 {
    a.wrapping_mul(b)
}

/// MC_03 — DIV8: 8-bit integer division, returns (quotient, remainder).
///
/// Division by zero returns `(0, 0)` — never panics.
///
/// ```
/// use brik64_core::mc::div8;
/// assert_eq!(div8(17, 5), (3, 2));
/// assert_eq!(div8(10, 0), (0, 0)); // safe
/// ```
pub fn div8(a: u8, b: u8) -> (u8, u8) {
    if b == 0 {
        (0, 0)
    } else {
        (a / b, a % b)
    }
}

/// MC_04 — MOD8: 8-bit modulo.
///
/// Modulo by zero returns `0` — never panics.
///
/// ```
/// use brik64_core::mc::mod8;
/// assert_eq!(mod8(17, 5), 2);
/// assert_eq!(mod8(10, 0), 0); // safe
/// ```
pub fn mod8(a: u8, b: u8) -> u8 {
    if b == 0 { 0 } else { a % b }
}

/// MC_05 — ABS64: Absolute value of a 64-bit signed integer.
///
/// `i64::MIN` returns `i64::MAX` (saturating).
///
/// ```
/// use brik64_core::mc::abs64;
/// assert_eq!(abs64(-42), 42);
/// assert_eq!(abs64(i64::MIN), i64::MAX);
/// ```
pub fn abs64(a: i64) -> i64 {
    if a == i64::MIN { i64::MAX } else { a.abs() }
}

/// MC_06 — NEG64: Negate a 64-bit signed integer.
///
/// `i64::MIN` returns `i64::MAX` (saturating).
///
/// ```
/// use brik64_core::mc::neg64;
/// assert_eq!(neg64(42), -42);
/// assert_eq!(neg64(i64::MIN), i64::MAX);
/// ```
pub fn neg64(a: i64) -> i64 {
    if a == i64::MIN { i64::MAX } else { -a }
}

/// MC_07 — CLAMP: Clamp a value to [lo, hi].
///
/// If `lo > hi`, returns `lo`.
///
/// ```
/// use brik64_core::mc::clamp;
/// assert_eq!(clamp(300, 0, 255), 255);
/// assert_eq!(clamp(-5, 0, 100), 0);
/// assert_eq!(clamp(50, 0, 100), 50);
/// ```
pub fn clamp(val: i64, lo: i64, hi: i64) -> i64 {
    val.clamp(lo, hi)
}

/// INC: increment u8 by 1, wrapping at 255→0.
///
/// ```
/// use brik64_core::mc::inc;
/// assert_eq!(inc(254), 255);
/// assert_eq!(inc(255), 0); // wraps
/// ```
pub fn inc(a: u8) -> u8 {
    a.wrapping_add(1)
}

/// DEC: decrement u8 by 1, wrapping at 0→255.
///
/// ```
/// use brik64_core::mc::dec;
/// assert_eq!(dec(1), 0);
/// assert_eq!(dec(0), 255); // wraps
/// ```
pub fn dec(a: u8) -> u8 {
    a.wrapping_sub(1)
}

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

    #[test]
    fn add8_wraps() {
        assert_eq!(add8(255, 1), 0);
        assert_eq!(add8(200, 100), 44);
    }

    #[test]
    fn sub8_wraps() {
        assert_eq!(sub8(0, 1), 255);
        assert_eq!(sub8(5, 10), 251);
    }

    #[test]
    fn div8_safe_zero() {
        assert_eq!(div8(10, 0), (0, 0));
    }

    #[test]
    fn clamp_all_cases() {
        assert_eq!(clamp(50, 0, 100), 50);
        assert_eq!(clamp(-1, 0, 100), 0);
        assert_eq!(clamp(200, 0, 100), 100);
    }
}
