""" Thread Service implementation """
import logging
import signal
from multiprocessing import Process, Value, Queue
from time import sleep, time

from ..utils.log import init_logging

logger = logging.getLogger(__name__)


class ProcessService(Process):
    """ Service that has start and stop methods and works as a daemon """
    def __init__(self, loglevel=logging.INFO):
        self.loglevel = loglevel
        self._is_running = Value('i', 0)
        self.cmd_queue = Queue()
        super().__init__(name=self.__class__.__name__, daemon=True)

    @property
    def is_running(self):
        """ Get _is_running safely """
        with self._is_running.get_lock():
            return self._is_running.value == 1

    @is_running.setter
    def is_running(self, value: bool):
        """ set _is_running safely """
        with self._is_running.get_lock():
            self._is_running.value = 1 if value else 0

    def start(self) -> None:
        """ Start the process """
        self.is_running = True
        super().start()

    def stop(self) -> None:
        """ Stop the process """
        self.is_running = False
        self.cmd_queue.put((0, None))

    def run(self) -> None:
        """ Routine """

        signal.signal(signal.SIGINT, lambda x, y: None)
        signal.signal(signal.SIGTERM, lambda x, y: None)
        init_logging(level=self.loglevel)

        last_refresh = time()
        while self.is_running:
            try:
                command = self.cmd_queue.get(timeout=1)
                self.handle_command(*command)
            except Exception as ex:
                exc_info = type(ex), ex, ex.__traceback__
                logger.error("main loop execution error", exc_info=exc_info)
            now = time()
            if time() - last_refresh >= 1:
                last_refresh = now
                self.cmd_queue.put_nowait((0,))
            sleep(0.001)  # sleep for 1ms to prevent 100% CPU load
        self.cmd_queue.close()
        logger.info(f"{self.name} has been stopped")

    def handle_command(self, command: int, *params) -> None:
        """ Handle command. Overwrite this in child classes """
        raise NotImplementedError()
