#!/usr/bin/env python3

from random import randint
from Cryptotools.Numbers.primeNumber import _millerRabinTest, isPrimeNumber
from Cryptotools.Utils.utils import gcd
from Cryptotools.lcm import lcm
from math import floor, log


def pollard_p_minus_1(n, B=None) -> int:
    """
        This function factorize the number n into factor based on the Pollard's p - 1 algorithm

        The first is to choose B, which is a positive integer and B < n
        In the second step, we need to define $M=\prod _{primes~q\leq B}q^{\lfloor \log_{q}{B}\rfloor }$

        Args:
            n (Integer): The number n to factorize

        Returns:
            Return the factorize of the number n or None
    """

    if B is None:
        B = randint(1, n - 1)
    # B = randint(1, n - 1)

    #### We define M
    # Select all prime numbers 1 < B
    q = list()
    for x in range(2, B):
        # with the _millerRabinTest, the program crash, because the randint() is empty
        # because, both min value and max value are 2
        # if _millerRabinTest(x):
        if isPrimeNumber(x):
            q.append(x)

    M = 1
    for prime in q:
        e = floor(log(B, prime))
        # print(prime, e)
        M *= pow(prime, e)

    # We choose a and coprime with n
    a = 2
    while True:
        if gcd(a, n) == 1:
            break
        a += 1
    
    # We can compute g = gcd((a ** M) - 1, n)
    g = gcd(pow(a, M, n) - 1, n)
    if g > 1:
        return g
    
    return None
