from collections.abc import Callable
from datetime import timedelta
from typing import Any, NamedTuple

__all__ = ("BaseBackend", "DisabledBackend", "KeyValueStoreBackend")

from celery.app.task import Context
from celery.exceptions import TimeoutError as CeleryTimeoutError
from celery.result import ResultSet
from typing_extensions import override

class pending_results_t(NamedTuple):
    concrete: dict[Any, Any]
    weak: dict[Any, Any]

class Backend:
    READY_STATES: frozenset[str]
    UNREADY_STATES: frozenset[str]
    EXCEPTION_STATES: frozenset[str]

    TimeoutError: type[CeleryTimeoutError]

    subpolling_interval: float | None
    supports_native_join: bool
    supports_autoexpire: bool
    persistent: bool

    retry_policy: dict[str, int | float]
    def __init__(
        self,
        app: Any,
        serializer: str | None = ...,
        max_cached_results: int | None = ...,
        accept: list[str] | None = ...,
        expires: float | timedelta | None = ...,
        expires_type: Callable[[Any], Any] | None = ...,
        url: str | None = ...,
        **kwargs: Any,
    ) -> None: ...
    def as_uri(self, include_password: bool = ...) -> str: ...
    def mark_as_started(self, task_id: str, **meta: Any) -> None: ...
    def mark_as_done(
        self,
        task_id: str,
        result: Any,
        request: Any = ...,
        store_result: bool = ...,
        state: str = ...,
    ) -> None: ...
    def mark_as_failure(
        self,
        task_id: str,
        exc: Exception,
        traceback: str | None = ...,
        request: Any = ...,
        store_result: bool = ...,
        call_errbacks: bool = ...,
        state: str = ...,
    ) -> None: ...
    def mark_as_revoked(
        self,
        task_id: str,
        reason: str = ...,
        request: Any = ...,
        store_result: bool = ...,
        state: str = ...,
    ) -> None: ...
    def mark_as_retry(
        self,
        task_id: str,
        exc: Exception,
        traceback: str | None = ...,
        request: Any = ...,
        store_result: bool = ...,
        state: str = ...,
    ) -> None: ...
    def store_result(
        self,
        task_id: str,
        result: Any,
        state: str,
        traceback: str | None = ...,
        request: Any = ...,
        **kwargs: Any,
    ) -> Any: ...
    def forget(self, task_id: str) -> None: ...
    def get_state(self, task_id: str) -> str: ...
    def get_result(self, task_id: str) -> Any: ...
    def get_children(self, task_id: str) -> list[Any] | None: ...
    def reload_task_result(self, task_id: str) -> None: ...
    def reload_group_result(self, group_id: str) -> None: ...
    def get_group_meta(self, group_id: str, cache: bool = ...) -> Any: ...
    def restore_group(self, group_id: str, cache: bool = ...) -> ResultSet | None: ...
    def cleanup(self) -> None: ...
    def process_cleanup(self) -> None: ...
    def apply_chord(
        self, header_result_args: tuple[Any, Any], body: Any, **kwargs: Any
    ) -> None: ...
    def current_task_children(self, request: Context | None = ...) -> list[Any]: ...
    def add_to_chord(self, chord_id: str, result: Any) -> None: ...
    def chord_error_from_stack(
        self, callback: Any, exc: Exception | None = None
    ) -> Exception: ...
    def decode(self, payload: bytes) -> Any: ...
    def decode_result(self, payload: bytes) -> Any: ...
    def delete_group(self, group_id: str) -> None: ...
    def encode(self, data: Any) -> bytes: ...
    def encode_result(self, result: Any, state: str) -> bytes: ...
    def ensure_chords_allowed(self) -> None: ...
    def exception_safe_to_retry(self, exc: Exception) -> bool: ...
    def exception_to_python(self, exc: Any) -> Exception: ...
    def fail_from_current_stack(
        self, task_id: str, exc: Exception | None = None
    ) -> None: ...
    def fallback_chord_unlock(
        self, header_result: Any, body: Any, countdown: int = 1, **kwargs: Any
    ) -> None: ...
    def get_status(self, task_id: str) -> str: ...
    def get_task_meta(self, task_id: str, cache: bool = True) -> dict[str, Any]: ...
    def get_traceback(self, task_id: str) -> str | None: ...
    def is_cached(self, task_id: str) -> bool: ...
    def meta_from_decoded(self, meta: dict[str, Any]) -> dict[str, Any]: ...
    def on_chord_part_return(
        self, request: Any, state: str, result: Any, **kwargs: Any
    ) -> None: ...
    def on_task_call(self, producer: Any, task_id: str) -> None: ...
    def prepare_exception(
        self, exc: Exception, serializer: str | None = None
    ) -> Any: ...
    def prepare_expires(
        self, value: float | timedelta | None, type: type | None = None
    ) -> float | None: ...
    def prepare_persistent(self, enabled: bool | None = None) -> bool: ...
    def prepare_value(self, result: Any) -> Any: ...
    def save_group(self, group_id: str, result: Any) -> None: ...
    def set_chord_size(self, group_id: str, chord_size: int) -> None: ...

class SyncBackendMixin:
    @property
    def is_async(self) -> bool: ...
    def add_pending_result(self, result: Any, weak: bool = False) -> Any: ...
    def remove_pending_result(self, result: Any) -> None: ...
    def iter_native(
        self,
        result: ResultSet,
        timeout: float | None = ...,
        interval: float = ...,
        no_ack: bool = ...,
        on_message: Callable[[Any], None] | None = ...,
        on_interval: Callable[[], None] | None = ...,
    ) -> None: ...
    def wait_for_pending(
        self,
        result: ResultSet,
        timeout: float | None = ...,
        interval: float = ...,
        no_ack: bool = ...,
        on_message: Callable[[Any], None] | None = ...,
        on_interval: Callable[[], None] | None = ...,
        callback: Callable[[Any], Any] | None = ...,
        propagate: bool = ...,
    ) -> None: ...
    def wait_for(
        self,
        task_id: str,
        timeout: float | None = ...,
        interval: float = ...,
        no_ack: bool = ...,
        on_interval: Callable[[], None] | None = ...,
    ) -> Any: ...

class BaseBackend(Backend, SyncBackendMixin): ...

class BaseKeyValueStoreBackend(Backend):
    chord_keyprefix: str
    group_keyprefix: str
    task_keyprefix: str
    implements_incr: bool
    key_t: Callable[[str], bytes]
    def get(self, key: str) -> Any: ...
    def mget(self, keys: list[str]) -> list[Any]: ...
    def set(self, key: str, value: Any) -> None: ...
    def delete(self, key: str) -> None: ...
    def incr(self, key: str) -> int: ...
    def expire(self, key: str, value: int) -> None: ...
    def get_key_for_chord(self, group_id: str, key: str = "") -> str: ...
    def get_key_for_group(self, group_id: str, key: str = "") -> str: ...
    def get_key_for_task(self, task_id: str, key: str = "") -> str: ...
    def get_many(
        self,
        task_ids: list[str],
        timeout: float | None = None,
        interval: float = 0.5,
        no_ack: bool = True,
        on_message: Callable[[Any], None] | None = None,
        on_interval: Callable[[], None] | None = None,
        max_iterations: int | None = None,
        READY_STATES: frozenset[str] = ...,
    ) -> Any: ...
    @override
    def on_chord_part_return(
        self, request: Any, state: str, result: Any, **kwargs: Any
    ) -> None: ...

class KeyValueStoreBackend(BaseKeyValueStoreBackend, SyncBackendMixin): ...

class DisabledBackend(BaseBackend):
    @override
    def store_result(self, *args: Any, **kwargs: Any) -> None: ...
    @override
    def ensure_chords_allowed(self) -> None: ...
    def get_many(self, *args: Any, **kwargs: Any) -> Any: ...
    @override
    def get_status(self, *args: Any, **kwargs: Any) -> str: ...
    def get_task_meta_for(self, *args: Any, **kwargs: Any) -> Any: ...
    @override
    def get_traceback(self, *args: Any, **kwargs: Any) -> str | None: ...
