from __future__ import annotations

from dataclasses import dataclass, field
from typing import Callable, Any
import logging


@dataclass(slots=True)
class RetryConfig:
    max_attempts: int = 3
    delay: float = 1.0
    backoff: str = "fixed"  # fixed, linear, exponential
    max_delay: float | None = None
    jitter: float = 0.0
    exceptions: tuple[type[BaseException], ...] = field(
        default_factory=lambda: (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

    def __post_init__(self) -> None:
        if self.max_attempts < 1:
            raise ValueError("max_attempts must be at least 1")
        if self.delay < 0:
            raise ValueError("delay must be >= 0")
        if self.jitter < 0:
            raise ValueError("jitter must be >= 0")
        if self.max_delay is not None and self.max_delay < 0:
            raise ValueError("max_delay must be >= 0")
        if self.backoff not in {"fixed", "linear", "exponential"}:
            raise ValueError("backoff must be one of: fixed, linear, exponential")
        if not self.exceptions:
            raise ValueError("exceptions must not be empty")
