import inspect


def func_params_mediator(params_bank, init_func):
    """
    Pass parameters to a function according to func's parameters list (through inspect package)

    Args:
        params_bank (list):
            List of the parameters bank. Each item must be the instance of ``dictionary`` or ``object``.
        init_func (func):
            Function to be called.
    
    Returns:
        The output of the function.
    """
    # get the completed params
    assert isinstance(params_bank, list)

    # check
    signature = inspect.getfullargspec(init_func)
    all_params = signature.args
    params_len = len(all_params)
    optional_len = (
        len(signature.defaults) 
        if signature.defaults is not None
        else 0
    )
    required_params = [item for item in all_params[:(params_len-optional_len)] if item != 'self']

    # construct params_dict
    curr_params = {}
    for params_name in all_params:
        for curr_bank in params_bank:
            if isinstance(curr_bank, dict):
                params_value = curr_bank.get(params_name, None)
            else:
                params_value = getattr(curr_bank, params_name, None)
            
            if params_value is not None:
                curr_params[params_name] = params_value

    assert all([item in list(curr_params.keys()) for item in required_params])
    return init_func(**curr_params)