from typing import Optional
from typing import Callable
import functools
from typing import Any
import warnings


def deprecated(*, deadline: str, fix: str,
               name: Optional[str] = None) -> Callable[[Callable], Callable]:
    """Marks a function as deprecated.

    Args:
        deadline: The version where the function will be deleted (e.g. "v0.7").
        fix: A complete sentence describing what the user should be using
            instead of this particular function (e.g. "Use cos instead.")
        name: How to refer to the function.
            Defaults to `func.__qualname__`.

    Returns:
        A decorator that decorates functions with a deprecation warning.
    """

    def decorator(func: Callable) -> Callable:

        @functools.wraps(func)
        def decorated_func(*args, **kwargs) -> Any:
            qualname = (func.__qualname__ if name is None else name)
            warnings.warn(
                f'{qualname} was used but is deprecated.\n'
                f'It will be removed in cirq {deadline}.\n'
                f'{fix}\n',
                DeprecationWarning,
                stacklevel=2)

            return func(*args, **kwargs)

        decorated_func.__doc__ = (
            f'THIS FUNCTION IS DEPRECATED.\n\n'
            f'IT WILL BE REMOVED IN `cirq {deadline}`.\n\n'
            f'{fix}\n\n'
            f'{decorated_func.__doc__ or ""}')

        return decorated_func

    return decorator