import asyncio
import logging
from typing import List, Optional, Union

from maps_adv.warden.client.lib.client import ClientFactory

from .tasks import PeriodicalTask


class TaskMaster:
    __slots__ = "_client_factory", "_tasks", "_running", "_logger"

    _client_factory: ClientFactory
    _running: List[asyncio.Task]
    _tasks: List[PeriodicalTask]

    def __init__(
        self,
        server_url: str,
        tasks: List[Union[PeriodicalTask]],
        *,
        logger: Optional = None,
    ):
        self._client_factory = ClientFactory(server_url)
        self._tasks = tasks
        self._running = []
        self._logger = logger if logger else logging.getLogger(__name__)

    async def run(self):
        for task in self._tasks:
            self._running.append(asyncio.create_task(task.run(self._client_factory)))

    async def stop(self):
        if not self._running:
            return

        for task in self._running:
            task.cancel()

        await asyncio.wait(self._running, return_when=asyncio.ALL_COMPLETED)

        for task in self._running:
            try:
                exception = task.exception()
                if exception:
                    self._logger.exception(exception, exc_info=exception)
            except asyncio.CancelledError:
                pass

        self._running = []
