from typing import Optional
from typing import Tuple


def wrap_slice(
    start: Optional[int],
    stop: Optional[int],
    step: Optional[int],
    length: Optional[int],
) -> Tuple[int, int, int]:
    """Wraps slice indices into a window.

    Arguments:
        start (int):
            :attr:`slice.start` index, or ``None``.

        stop (int):
            :attr:`slice.stop` index, or ``None``.

        step (int):
            :attr:`slice.step` value, or ``None``.

        length (int):
            Exclusive end of the virtual range to wrap, or ``None``.

    Returns:
        tuple of int: Wrapped slice parameters.

    Examples:
        >>> wrap_slice(3, 5, 1, 7)
        (3, 5, 1)

        >>> wrap_slice(-3, 5, 1, 7)
        (4, 5, 1)

        >>> wrap_slice(3, -5, 1, 7)
        (3, 2, 1)

        >>> wrap_slice(-3, -5, 1, 7)
        (4, 2, 1)

        >>> wrap_slice(None, 5, 1, 7)
        (0, 5, 1)

        >>> wrap_slice(3, None, 1, 7)
        (3, 7, 1)

        >>> wrap_slice(3, 5, None, 7)
        (3, 5, 1)

        >>> wrap_slice(3, 5, 1, None)
        (0, 0, 1)
    """
    if step is None:
        step = 1

    if length:
        if start is None:
            start = 0
        elif not 0 <= start < length:
            start %= length

        if stop is None:
            stop = length
        elif not 0 <= stop < length:
            stop %= length
    else:
        start = 0
        stop = 0

    return start, stop, step