"""Helper functions."""

import datetime
import functools
import warnings
from collections.abc import Callable
from typing import Any, Dict, List, Optional, Type

import axipy

__all__: List[str] = [
    "_deprecated_by",
    "_run_in_gui_decor",
    "_experimental",
    "_experimental_class",
    "_try_except_silent",
    "_back_compat_params",
]


def _deprecated_by(use_instead: Optional[str] = None) -> Callable:
    def decorate(func: Callable) -> Callable:

        # Автоматическое исключение задекорированных методов sphinx-ом.
        doc = func.__doc__
        if isinstance(doc, str) and ":meta private:" not in doc:
            func.__doc__ += "\n:meta private:"  # type: ignore[operator]

        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            if use_instead is None:
                msg = f"'{func.__name__}' is deprecated."
            else:
                msg = f"'{func.__name__}' is deprecated, use '{use_instead}' instead."
            warnings.warn(msg, DeprecationWarning, stacklevel=2)
            result = func(*args, **kwargs)
            return result

        return wrapper

    return decorate


def _run_in_gui_decor(func: Callable) -> Callable:
    @functools.wraps(func)
    def inner(*args: Any, **kwargs: Any) -> Any:
        return axipy.run_in_gui(func, *args, **kwargs)

    return inner


def _experimental(_removal_date: Optional[datetime.date] = None) -> Callable:
    def decorate(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            return func(*args, **kwargs)

        return wrapper

    return decorate


def _experimental_class(_removal_date: Optional[datetime.date] = None) -> Callable:
    def decorate(cls: Type) -> Callable:
        return cls

    return decorate


def _try_except_silent(func: Callable) -> Callable:
    @functools.wraps(func)
    def inner(*args: Any, **kwargs: Any) -> Any:
        try:
            result = func(*args, **kwargs)
        except Exception:
            pass
        else:
            return result

    return inner


def _back_compat_params(params: Dict[str, str]) -> Callable:
    def decorate(func: Callable) -> Callable:

        @functools.wraps(func)
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            if kwargs:
                for k, v in params.items():
                    if (k in kwargs) and (v not in kwargs):
                        kwargs[v] = kwargs[k]
                        del kwargs[k]

            result = func(*args, **kwargs)
            return result

        return wrapper

    return decorate
