import timeit
import secrets
import math

primes = (0x3FFFFFFB, 0x3FFFFF29, 0x3FFFFF0B, 0x2FFFFFFF, 0x2FFFFF5B)

# --- Lógica Actual (Bucle) ---
def get_multiplier_current(i, multiplier, primes, p_len, jumps, jump):
    value = (i + multiplier + primes[(i + jump) % p_len]) & 0x3FFFFFFF
    for _ in range(jumps):
        shift = 13 + i % 8
        if i & 1:
            value ^= (value >> shift)
        else:
            value ^= (value << shift)
        value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF
    return value

# --- Lógica Optimizada (Unrolled) ---
def get_multiplier_fast(i, multiplier, primes, p_len, jump):
    # Asumiendo que jumps siempre es 3
    value = (i + multiplier + primes[(i + jump) % p_len]) & 0x3FFFFFFF
    
    # Salto 1
    shift = 13 + i % 8
    value ^= (value >> shift if i & 1 else value << shift)
    value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF
    
    # Salto 2
    shift = 13 + i % 8
    value ^= (value >> shift if i & 1 else value << shift)
    value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF
    
    # Salto 3
    shift = 13 + i % 8
    value ^= (value >> shift if i & 1 else value << shift)
    value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF
    
    return value

# --- 2. Lógica con While ---
def get_multiplier_while(i, multiplier, primes, p_len, jumps, jump):
    value = (i + multiplier + primes[(i + jump) % p_len]) & 0x3FFFFFFF
    count = 0
    while count < jumps:
        shift = 13 + i % 8
        if i & 1:
            value ^= (value >> shift)
        else:
            value ^= (value << shift)
        value = (value + primes[i := (i + jump) % p_len]) & 0x3FFFFFFF
        count += 1
    return value

def get_multiplier_callback(multiplier, primes, p_len, jumps, jump, i = 0):
    value = ((value ^ (
        value >> shift if i & 1 else value << shift
    )) + self.__primes[
        i := (i + self.__multiplier_jump) % self.__primes_l
    ]) & 0x3FFFFFFF

# --- Configuración del Test ---
primes = (0x3FFFFFFB, 0x3FFFFF29, 0x3FFFFF0B, 0x2FFFFFFF, 0x2FFFFF5B)
setup_code = """
from __main__ import get_multiplier_current, get_multiplier_fast, primes
import secrets
"""

# Ejecución de 1 millón de iteraciones
n = 1_000_000

t_current = timeit.timeit(lambda: get_multiplier_current(5, 1, primes, 5, 3, 7), setup=setup_code, number=n)
t_fast = timeit.timeit(lambda: get_multiplier_fast(5, 1, primes, 5, 7), setup=setup_code, number=n)
t_secrets = timeit.timeit(lambda: secrets.token_bytes(4), setup=setup_code, number=n)
t_while = timeit.timeit(lambda: get_multiplier_while(5, 1, primes, 5, 3, 7), setup=setup_code, number=n)

print(f"--- Resultados ({n} iteraciones) ---")
print(f"Anyanka (Bucle):     {t_current:.4f} seg")
print(f"Anyanka (Unrolled):  {t_fast:.4f} seg")
print(f"Secrets (Cripto):    {t_secrets:.4f} seg")
print(f"Anyanka (While):     {t_while:.4f} seg")