from typing import Union


def generate_calls(
    n: Union[int, list],
    Date,
    n_shooting: tuple,
    dynamics_types: list,
    ode_solver: list,
    nstep: int,
    n_threads: int,
    out_path_raw: str,
    model_str: str,
    extra_obj: bool,
) -> list:
    """
    Generate the list of calls to be used in multiprocessing

    Parameters
    ----------
    n : Union[int, list]
        The int of list of irand to be run
    Date : str
        The date of the run
    n_shooting : tuple
        The number of shooting points for each phase
    dynamics_types : list
        The list of dynamics types to be run such as MillerDynamics.EXPLICIT, MillerDynamics.IMPLICIT, MillerDynamics.EXPLICIT_IMPLICIT
    ode_solver : list
        The list of OdeSolver to be run such as OdeSolver.RK4, OdeSolver.RK2
    nstep : int
        The number of intermediate steps between two shooting points
    n_threads : int
        The number of threads to be used
    out_path_raw : str
        The path to store the raw results
    model_str : str
        The path to the bioMod model
    extra_obj : bool
        Whether to run with the extra objective or not (minimizing extra controls for implicit formulations)

    Returns
    -------
    calls: list
        The list of calls to be run
    """
    if isinstance(n, int):
        rand_loop = range(n)
    else:
        rand_loop = n
    calls = []
    for i, dynamics_type in enumerate(dynamics_types):
        for i_rand in rand_loop:  # Should be 100
            calls.append(
                [
                    Date,
                    i_rand,
                    n_shooting,
                    dynamics_type,
                    ode_solver[i],
                    nstep,
                    n_threads,
                    out_path_raw,
                    model_str,
                    extra_obj,
                ]
            )
    return calls