from datetime import datetime
from logging import Logger
from threading import Thread
from typing import Callable

from .base import App

LOOP_TIMEOUT: float = ...

JobFunction = Callable[[], None]
Cron = str | SchedulerDate
CronField = str | int | list | tuple

class Scheduler(Thread):
    owner: App | None
    timeout: float
    daemon: bool

    def __init__(self, owner: App | None, timeout: float = ..., daemon: bool = ...): ...
    def run(self): ...
    def stop(self): ...
    def tick(self): ...
    def load(self): ...
    def awake(self): ...
    @property
    def logger(self) -> Logger: ...

class CronScheduler(Scheduler):
    def __init__(self, owner: App | None, timeout: float = ..., daemon: bool = ...): ...
    def tick(self, now_ts: float | None = ...): ...
    def schedule(
        self,
        job: JobFunction,
        cron: Cron,
        id: str | None = ...,
        description: str | None = ...,
        now: datetime | None = ...,
    ) -> SchedulerTask: ...
    def next_run(self) -> datetime | None: ...
    def next_timestamp(self) -> float | None: ...

class SchedulerTask(object):
    job: JobFunction
    date: SchedulerDate

    def __init__(
        self,
        job: JobFunction,
        cron: Cron,
        id: str | None = ...,
        description: str | None = ...,
    ): ...
    def enable(self): ...
    def disable(self): ...
    def next_run(self, now: datetime | None = ...) -> datetime: ...
    def next_timestamp(self, now: datetime | None = ...) -> float: ...
    @property
    def enabled(self) -> bool: ...
    @property
    def cron(self) -> str: ...

class SchedulerDate(object):
    minutes: set[int]
    hours: set[int]
    days_of_month: set[int]
    months: set[int]
    days_of_week: set[int]

    def __init__(
        self,
        minutes: CronField = ...,
        hours: CronField = ...,
        days_of_month: CronField = ...,
        months: CronField = ...,
        days_of_week: CronField = ...,
    ): ...
    @classmethod
    def from_cron(cls, cron: Cron) -> SchedulerDate: ...
    def into_cron(self) -> str: ...
    def next_timestamp(self, now: datetime | None = None) -> float: ...
    def next_run(self, now: datetime | None = None) -> datetime: ...
    def _parse_field(
        self, field: CronField, min_value: int, max_value: int
    ) -> set[int]: ...
    def _into_cron_field(
        self, field: set[int], min_value: int, max_value: int
    ) -> str: ...
