import logging
import time
from threading import (
    Thread,
)
from typing import (
    Optional,
)

from opentelemetry import trace
from ._EventQueue import EventQueue
from ._Publisher import Publisher

tracer = trace.get_tracer(__name__)
logger = logging.getLogger(__name__)


class PublishQueue:
    def __init__(
        self,
        publisher: Publisher,
        event_queue: EventQueue,
    ):
        self.publisher = publisher
        self.event_queue = event_queue

        self.running = False
        self.thread: Optional[Thread] = None

    def start(self):
        self.running = True

        self.thread = Thread(
            target=self._publish_runner,
            name="PublishQueueThread",
        )
        self.thread.daemon = True
        self.thread.start()

    def stop(self):
        logger.info("Stopping PublishQueue")
        self.running = False
        self.thread.join()
        self.thread = None

    def _publish_runner(self):
        while self.running:
            try:
                self._publisher_loop()
            except Exception as ex:
                logger.exception("Error processing event", exc_info=ex)
                time.sleep(1)

    def _publisher_loop(self):
        logger.info("Executing publisher loop")
        to_publish_list = self.event_queue.get_events_that_need_to_be_published_now()
        if len(to_publish_list) == 0:
            self.event_queue.wait_for_new_events()
            return

        self._try_to_publish_events(to_publish_list=to_publish_list)

    def _try_to_publish_events(
        self,
        to_publish_list
    ):
        for to_publish in to_publish_list:
            self.publisher.publish_event(publish_detail=to_publish)
