from __future__ import annotations

import inspect
import logging
from functools import wraps
from typing import Callable, Any

from .config import RetryConfig
from .core import run_async, run_sync


def retry(
    *,
    max_attempts: int = 3,
    delay: float = 1.0,
    backoff: str = "fixed",
    max_delay: float | None = None,
    jitter: float = 0.0,
    exceptions: tuple[type[BaseException], ...] = (Exception,),
    raise_last: bool = True,
    on_retry: Callable[..., None] | None = None,
    before_retry: Callable[..., None] | None = None,
    after_retry: Callable[..., None] | None = None,
    retry_if_result: Callable[[Any], bool] | None = None,
    logger: logging.Logger | None = None,
    log_level: int = logging.WARNING,
    timeout: float | None = None,
):
    config = RetryConfig(
        max_attempts=max_attempts,
        delay=delay,
        backoff=backoff,
        max_delay=max_delay,
        jitter=jitter,
        exceptions=exceptions,
        raise_last=raise_last,
        on_retry=on_retry,
        before_retry=before_retry,
        after_retry=after_retry,
        retry_if_result=retry_if_result,
        logger=logger,
        log_level=log_level,
        timeout=timeout,
    )

    def decorator(func):
        if inspect.iscoroutinefunction(func):

            @wraps(func)
            async def async_wrapper(*args, **kwargs):
                return await run_async(func, config, *args, **kwargs)

            return async_wrapper

        @wraps(func)
        def sync_wrapper(*args, **kwargs):
            return run_sync(func, config, *args, **kwargs)

        return sync_wrapper

    return decorator
