import logging
from datetime import (
    datetime,
    timedelta,
)
from threading import Thread
from typing import (
    Callable,
    Optional,
)

from maintenance_util import MaintenanceWindow
from timeutil import (
    AwakableSleeper,
    ConditionSleeper,
)


logger = logging.getLogger(__name__)


class MaintenanceWindowManager(object):
    def __init__(
        self,
        maintenance_window: MaintenanceWindow,
        func: Callable[[], None],
        run_on_start: bool = True,
        sleeper: Optional[AwakableSleeper] = None
    ):
        self.maintenance_window = maintenance_window
        self.func = func
        self.run_on_start = run_on_start
        self.sleeper = sleeper or ConditionSleeper()
        self.thread: Optional[Thread] = None
        self.running = False


    def start(self):
        if self.run_on_start:
            logger.debug("Initializing manager, running func...")
            self.func()

        self.running = True
        self.thread = Thread(target=self._run, daemon=True)
        self.thread.start()

    def stop(self):
        self.running = False
        self.sleeper.wake_up()
        if self.thread:
            self.thread.join()

    def _run(self):
        while self.running:
            if self.maintenance_window.is_inside():
                logger.debug("Inside maintenance window, running func...")
                self.func()

            amount_to_sleep = self.maintenance_window.seconds_to_next()
            until = datetime.now() + timedelta(seconds=amount_to_sleep)
            logger.debug("Sleeping for %d seconds until %s", amount_to_sleep, until)
            self.sleeper.sleep(amount_to_sleep)
