from typing import Iterable
from typing import Optional
from typing import Callable
from typing import Any


def iterable_repr(
    iterable: Iterable,
    prefix: str = "[",
    template: str = "{value}",
    separator: str = ", ",
    suffix: str = "]",
    sorting: bool = False,
    sort_key: Optional[Callable[[Any], Any]] = None,
    reverse: bool = False,
    value_repr: Callable[[Any], str] = repr,
) -> str:
    """
    Get custom representation of an iterable.

    :param iterable: Iterable.
    :param prefix: Prefix.
    :param template: Item format template ({key} and {value}).
    :param separator: Separator.
    :param suffix: Suffix.
    :param sorting: Whether to sort the iterable or not.
    :param sort_key: Sorting key.
    :param reverse: Reverse sorting.
    :param value_repr: Value representation function.
    :return: Custom representation.
    """
    parts = []
    if sorting:
        iterable = sorted(iterable, key=sort_key, reverse=reverse)
    for value in iterable:
        part = template.format(value=value_repr(value))
        parts.append(part)
    return prefix + separator.join(parts) + suffix