"""Positional argument deprecation decorator."""
import inspect
from functools import wraps
from inspect import iscoroutinefunction
from typing import Any, Callable, Tuple
from warnings import warn


def _deprecate_args(*old_args: str):
    def _generate_arg_string(used_args: Tuple[str, ...]) -> str:
        used_args = list(map(repr, used_args))
        arg_count = len(used_args)
        arg_string = (
            " and ".join(used_args)
            if arg_count < 3
            else f"{', '.join(used_args[:-1])}, and {used_args[-1]}"
        )
        arg_string += f" as {'' if arg_count > 1 else 'a '}"
        arg_string += "keyword argument"
        return arg_string + ("s" if arg_count > 1 else "")

    def wrapper(func: Callable):
        @wraps(func)
        def _wrapper(*args: Any, **kwargs: Any):
            signature = inspect.signature(func)
            positional_args = [
                name
                for name, parameter in signature.parameters.items()
                if parameter.kind is inspect.Parameter.POSITIONAL_OR_KEYWORD
            ]
            _old_args = tuple(filter(lambda arg: arg not in positional_args, old_args))
            if positional_args:
                # remove the acceptable positional arguments like self or id for helpers
                kwargs.update(zip(positional_args, args))
                args = tuple(args[len(positional_args) :])
            if args:
                arg_string = _generate_arg_string(_old_args[: len(args)])
                warn(
                    f"Positional arguments for {func.__qualname__!r} will no longer be"
                    f" supported in Async PRAW 8.\nCall this function with"
                    f" {arg_string}.",
                    DeprecationWarning,
                    stacklevel=2,
                )
            return func(**dict(zip(_old_args, args)), **kwargs)

        if iscoroutinefunction(func):

            @wraps(func)
            async def wrapped(*args: Any, **kwargs: Any):
                return await _wrapper(*args, **kwargs)

        else:

            @wraps(func)
            def wrapped(*args: Any, **kwargs: Any):
                return _wrapper(*args, **kwargs)

        return wrapped

    return wrapper
