//! F3 — Control monomers: MC_24–MC_31
//!
//! Flow control primitives. All operations are total.

/// MC_24 — IF: Conditional selection.
///
/// Returns `then_val` if `cond` is true, else `else_val`.
///
/// ```
/// use brik64_core::mc::mc_if;
/// assert_eq!(mc_if(true, 1i64, 2), 1);
/// assert_eq!(mc_if(false, 1i64, 2), 2);
/// ```
pub fn mc_if<T>(cond: bool, then_val: T, else_val: T) -> T {
    if cond { then_val } else { else_val }
}

/// MC_25 — LOOP: Apply a function `n` times, threading the accumulator.
///
/// Equivalent to `f(f(f(...f(init)...)))` n times.
/// `n` is capped at 1_000_000 to guarantee termination.
///
/// ```
/// use brik64_core::mc::mc_loop;
/// let result = mc_loop(5, 0i64, |acc| acc + 1);
/// assert_eq!(result, 5);
/// ```
pub fn mc_loop<T, F>(n: usize, init: T, f: F) -> T
where
    F: Fn(T) -> T,
{
    let n = n.min(1_000_000);
    let mut acc = init;
    for _ in 0..n {
        acc = f(acc);
    }
    acc
}

/// MC_26 — NOP: No operation. Returns its argument unchanged.
pub fn nop<T>(val: T) -> T { val }

/// MC_27 — HALT: Signal halting condition — returns the exit code.
/// In library context this is a typed no-op; the exit code is returned as-is.
pub fn halt(code: i64) -> i64 { code }

/// MC_28 — CMP_EQ: Equality comparison.
pub fn cmp_eq(a: i64, b: i64) -> bool { a == b }

/// MC_29 — CMP_LT: Less-than comparison.
pub fn cmp_lt(a: i64, b: i64) -> bool { a < b }

/// MC_30 — CMP_GT: Greater-than comparison.
pub fn cmp_gt(a: i64, b: i64) -> bool { a > b }

/// MC_31 — CALL: Apply a function to an argument. Enables higher-order composition.
///
/// ```
/// use brik64_core::mc::mc_call;
/// let result = mc_call(|x: i64| x * 2, 21);
/// assert_eq!(result, 42);
/// ```
pub fn mc_call<A, B, F: Fn(A) -> B>(f: F, arg: A) -> B {
    f(arg)
}
