//! Integration tests for end-to-end workflows.

use clock_bigint::{BigInt, BigIntCore, MontgomeryContext, from_mont, mod_pow, mont_mul, to_mont};

#[test]
fn test_montgomery_consistency() {
    // Test: from_mont(MontMul(to_mont(a), to_mont(b))) == (a*b mod m)
    let modulus = BigInt::from_u64(97, 10); // Prime
    let ctx = MontgomeryContext::new(modulus.clone()).unwrap();

    // Debug: Print Montgomery context values
    println!("Modulus: {}", modulus.limbs()[0]);
    println!("R: {}", ctx.r().limbs()[0]);
    println!("R²: {}", ctx.r_squared().limbs()[0]);
    println!("m_prime: {}", ctx.m_prime());

    // Manual computation for verification
    let mut manual_r = 1u128;
    for _ in 0..64 {
        manual_r = (manual_r * 2) % (97u128);
    }
    println!("Manual R (2^64 mod 97): {}", manual_r);

    let manual_r2 = ((manual_r as u128) * (manual_r as u128)) % (97u128);
    println!("Manual R² ((2^64 mod 97)² mod 97): {}", manual_r2);

    let a = BigInt::from_u64(5, 10);
    let b = BigInt::from_u64(7, 10);

    let a_mont = to_mont(&ctx, &a).unwrap();
    println!("a_mont: {}", a_mont.limbs()[0]);

    let b_mont = to_mont(&ctx, &b).unwrap();
    println!("b_mont: {}", b_mont.limbs()[0]);

    let c_mont = mont_mul(&ctx, &a_mont, &b_mont).unwrap();
    println!("c_mont: {}", c_mont.limbs()[0]);

    let c = from_mont(&ctx, &c_mont).unwrap();
    println!("c: {}", c.limbs()[0]);

    // The implementation uses a specific Montgomery representation
    // 5 * 7 = 35, 35 mod 97 = 35
    assert_eq!(c.limbs()[0], 35);
}

#[test]
fn test_modular_exponentiation_simple() {
    let modulus = BigInt::from_u64(97, 10);
    let ctx = MontgomeryContext::new(modulus).unwrap();

    let base = BigInt::from_u64(5, 10);
    let exponent = BigInt::from_u64(3, 10);

    let result = mod_pow(&ctx, &base, &exponent).unwrap();

    // 5^3 = 125, 125 mod 97 = 28
    assert_eq!(result.limbs()[0], 28);
}

#[test]
fn test_modular_exponentiation_exponent_zero() {
    let modulus = BigInt::from_u64(97, 10);
    let ctx = MontgomeryContext::new(modulus).unwrap();

    let base = BigInt::from_u64(5, 10);
    let exponent = BigInt::from_u64(0, 10);

    let result = mod_pow(&ctx, &base, &exponent).unwrap();

    // base^0 = 1 mod m
    assert_eq!(result.limbs()[0], 1);
}

#[test]
fn test_modular_exponentiation_base_zero() {
    let modulus = BigInt::from_u64(97, 10);
    let ctx = MontgomeryContext::new(modulus).unwrap();

    let base = BigInt::from_u64(0, 10);
    let exponent = BigInt::from_u64(5, 10);

    let result = mod_pow(&ctx, &base, &exponent).unwrap();

    // 0^exponent = 0 mod m (if exponent > 0)
    assert_eq!(result.limbs()[0], 0);
}

// Note: RSA and secp256k1 test vectors would require:
// - Known test vectors from standards
// - Proper implementation of R and R² computation
// - Full Montgomery reduction implementation
// These are placeholders for when the full implementation is complete.
