import asyncio

from ..time import Time
from ..config import Startable
from ..logger import getLogger

logger = getLogger(__name__)


class StopWorkException(Exception):
    pass


class Worker(Startable):
    def __init__(self, name, method, time: Time, interval=1):
        super().__init__()
        self._method = method
        self._time = time
        self._name = name
        self._last_error = None
        self._interval = interval
        self._task = None
        self._should_stop = False
        self._wait_event = asyncio.Event()

    async def work(self):
        while not self._should_stop:
            self._wait_event.clear()
            try:
                await self._method()
            except StopWorkException:
                break
            except asyncio.CancelledError:
                break
            except Exception as e:
                self._last_error = e
                logger.error(
                    "Worker {0} got an unexpected error".format(self._name))
                logger.printException(e)
            if isinstance(self._interval, float) or isinstance(self._interval, int):
                interval = self._interval
            else:
                interval = self._interval()
            await self._time.sleepAsync(interval, self._wait_event)

    async def start(self):
        self._should_stop = False
        self._task = asyncio.create_task(self.work(), name=self._name)
        return self._task

    async def stop(self):
        self._should_stop = True
        if self._task is not None:
            self._task.cancel()
            await asyncio.wait([self._task])

    def isRunning(self):
        if self._task is None:
            return False
        return not self._task.done()

    def getLastError(self):
        return self._last_error
