import logging
from typing import Dict

from crontab import CronTab
from messagebus import MessageBus, Event
from timeutil import Clock, Sleeper

from ._EventDefinition import EventDefinition
from ._InvalidCronTabExpression import InvalidCronTabExpression

logger = logging.getLogger("SchedComp")


class CronTabInteractor(object):
    def __init__(self, message_bus, expression, event_definition, clock, sleeper):
        # type: (MessageBus, str, EventDefinition, Clock, Sleeper) -> None
        self.clock = clock
        self.sleeper = sleeper
        self.message_bus = message_bus
        self.event_definition = event_definition

        try:
            self.entry = CronTab(expression)
        except ValueError:
            raise InvalidCronTabExpression(expression)

    def execute(self):
        sleep_time = self.entry.next(self.clock.now(), default_utc=False)
        self.sleeper.sleep(sleep_time)
        logger.info("Publishing event: {}".format(self.event_definition.subject))
        for headers in self.event_definition.headers:
            logger.info("Publishing event: {} for context {}".format(self.event_definition.subject, headers))
            self.message_bus.publish_event(self.build_event(headers))

    def build_event(self, headers: Dict[str, str]):
        return Event(subject=self.event_definition.subject,
                     event_type=self.event_definition.event_type,
                     data=self.event_definition.data,
                     headers=headers)
