import shelve
from collections.abc import Callable
from datetime import datetime
from threading import Thread
from typing import Any, NamedTuple

import kombu
from celery.app.base import Celery
from celery.schedules import BaseSchedule
from typing_extensions import override

__all__ = (
    "EmbeddedService",
    "PersistentScheduler",
    "ScheduleEntry",
    "Scheduler",
    "SchedulingError",
    "Service",
)

class SchedulingError(Exception): ...

class BeatLazyFunc:
    def __init__(self, func: Callable[..., Any], *args: Any, **kwargs: Any) -> None: ...
    def __call__(self) -> Any: ...
    def delay(self) -> Any: ...

class ScheduleEntry:
    total_run_count: int
    name: str | None
    task: str | None
    last_run_at: datetime | None
    schedule: BaseSchedule | None
    args: tuple[Any, ...] | None
    kwargs: dict[str, Any] | None
    options: dict[str, Any] | None
    relative: bool
    app: Celery | None

    def __init__(
        self,
        name: str | None = None,
        task: str | None = None,
        last_run_at: datetime | None = None,
        total_run_count: int | None = None,
        schedule: BaseSchedule | None = None,
        args: tuple[Any, ...] = (),
        kwargs: dict[str, Any] | None = None,
        options: dict[str, Any] | None = None,
        relative: bool = False,
        app: Celery | None = None,
    ) -> None: ...
    def __ge__(self, other: ScheduleEntry) -> bool: ...
    def __gt__(self, other: ScheduleEntry) -> bool: ...
    def __le__(self, other: ScheduleEntry) -> bool: ...
    def __lt__(self, other: ScheduleEntry) -> bool: ...
    def __iter__(self) -> ScheduleEntry: ...
    def __next__(self, last_run_at: datetime | None = None) -> ScheduleEntry: ...
    def default_now(self) -> datetime: ...
    def editable_fields_equal(self, other: ScheduleEntry) -> bool: ...
    def is_due(self) -> tuple[bool, float]: ...
    def next(self, last_run_at: datetime | None = None) -> ScheduleEntry: ...
    def update(self, other: ScheduleEntry) -> None: ...

class event_t(NamedTuple):
    time: float
    priority: int
    entry: ScheduleEntry

class Scheduler:
    Entry: type[ScheduleEntry]
    app: Celery
    schedule: dict[str, ScheduleEntry]
    max_interval: int | None
    lazy: bool

    def __init__(
        self,
        app: Celery,
        schedule: dict[str, ScheduleEntry] | None = None,
        max_interval: int | None = None,
        Producer: type[kombu.Producer] | None = None,
        lazy: bool = False,
        sync_every_tasks: int | None = None,
        **kwargs: Any,
    ) -> None: ...
    def setup_schedule(self) -> None: ...
    def sync(self) -> None: ...
    def close(self) -> None: ...
    def add(self, **kwargs: Any) -> ScheduleEntry: ...
    def adjust(self, n: int, drift: float = -0.01) -> float: ...
    def apply_async(
        self,
        entry: ScheduleEntry,
        producer: kombu.Producer | None = None,
        advance: bool = True,
        **kwargs: Any,
    ) -> Any: ...
    def apply_entry(
        self, entry: ScheduleEntry, producer: kombu.Producer | None = None
    ) -> Any: ...
    @property
    def connection(self) -> kombu.Connection: ...
    def get_schedule(self) -> dict[str, ScheduleEntry]: ...
    @property
    def info(self) -> str: ...
    def install_default_entries(self, data: dict[str, Any]) -> None: ...
    def is_due(self, entry: ScheduleEntry) -> tuple[bool, float]: ...
    @property
    def logger(self) -> Any: ...
    def merge_inplace(self, b: dict[str, ScheduleEntry]) -> None: ...
    def populate_heap(
        self, event_t: type[event_t] = ..., heapify: Callable[[list[Any]], None] = ...
    ) -> None: ...
    @property
    def producer(self) -> kombu.Producer: ...
    def reserve(self, entry: ScheduleEntry) -> event_t: ...
    def schedules_equal(
        self,
        old_schedules: dict[str, ScheduleEntry],
        new_schedules: dict[str, ScheduleEntry],
    ) -> bool: ...
    def send_task(self, *args: Any, **kwargs: Any) -> Any: ...
    def set_schedule(self, schedule: dict[str, ScheduleEntry]) -> None: ...
    def should_sync(self) -> bool: ...
    @property
    def sync_every(self) -> int: ...
    @property
    def sync_every_tasks(self) -> int | None: ...
    def tick(
        self,
        event_t: type[event_t] = ...,
        min: Callable[..., Any] = ...,
        heappop: Callable[..., Any] = ...,
        heappush: Callable[..., Any] = ...,
    ) -> float: ...
    def update_from_dict(self, dict_: dict[str, Any]) -> None: ...

class PersistentScheduler(Scheduler):
    persistence: type[shelve.Shelf[Any]]
    known_suffixes: tuple[str, ...]
    @override
    def __init__(self, *args: Any, **kwargs: Any) -> None: ...
    @override
    def setup_schedule(self) -> None: ...
    @override
    def sync(self) -> None: ...
    @override
    def close(self) -> None: ...
    @override
    def get_schedule(self) -> dict[str, ScheduleEntry]: ...
    @override
    def set_schedule(self, schedule: dict[str, ScheduleEntry]) -> None: ...
    @property
    @override
    def info(self) -> str: ...

class Service:
    scheduler_cls: type[PersistentScheduler]
    app: Celery
    max_interval: int | None

    def __init__(
        self,
        app: Celery,
        max_interval: int | None = None,
        schedule_filename: str | None = None,
        scheduler_cls: type[Scheduler] | None = None,
    ) -> None: ...
    def start(self, embedded_process: bool = ...) -> None: ...
    def sync(self) -> None: ...
    def stop(self, wait: bool = ...) -> None: ...
    def get_scheduler(
        self, lazy: bool = ..., extension_namespace: str = ...
    ) -> Scheduler: ...
    @property
    def scheduler(self) -> Scheduler: ...

class _Threaded(Thread):
    daemon: bool
    name: str
    app: Celery

    def __init__(self, app: Celery, **kwargs: Any) -> None: ...
    @override
    def run(self) -> None: ...
    def stop(self) -> None: ...

class _Process:
    name: str
    app: Celery

    def __init__(self, app: Celery, **kwargs: Any) -> None: ...
    def run(self) -> None: ...
    def stop(self) -> None: ...

def EmbeddedService(
    app: Celery, max_interval: int | None = None, **kwargs: Any
) -> _Threaded | _Process: ...
