from typing import Mapping
from typing import Any
from typing import Iterable
from typing import Dict
import itertools


def _combinations_of_selections(selections: Mapping[str, Any]) -> Iterable[Dict[str, Any]]:
    """Find all permutations of combinations of selections.

    This is useful for passing the selections as kwargs to a function (perhaps for formatting).
    As a concrete example,

    ```python
    >>> selections = {"a": [1], "b": [2, 3]}
    >>> list(_combinations_of_selections(selections))
    [{'a': 1, 'b': 2}, {'a': 1, 'b': 3}]

    ```

    Note:
        The arguments are validated such that if there is only a single value for a given selection,
        it is converted to a list of length 1. Of course, it will be returned as a single value in
        the arguments.

    Args:
        selections: Selections from the dataset.
    Returns:
        Iterable whose elements contain dicts containing the arguments for each combination.
    """
    # Validation
    sels = {k: [v] if not isinstance(v, list) else v for k, v in selections.items()}
    # Return all combinations in a dict, such that they can be used as kwargs
    # See: https://stackoverflow.com/a/15211805
    return (dict(zip(sels, v)) for v in itertools.product(*sels.values()))