import asyncio
from typing import Coroutine, List

import sentry_sdk
from aiohttp import web
from sentry_sdk.integrations.aiohttp import AioHttpIntegration

from smb.common.multiruntime.lib import revision

from maps_adv.warden.client.lib import PeriodicalTask, TaskMaster

from . import api, tasks
from .config import config


class Application:
    api: web.Application = None
    tasks_to_start: List[Coroutine] = []
    started_tasks: List[Coroutine] = []
    warden_task_master: TaskMaster = None

    def __init__(self):
        config.init()

        self.api = api.create()

        self._setup_tasks()
        self._init_sentry()

    def _setup_tasks(self):
        self.tasks_to_start = [
            getattr(tasks, name).schedule(config.RELAUNCH_INTERVAL)
            for name in config.TASKS_TO_START
        ]

        self.api.on_startup.append(self._start_tasks)
        self.api.on_cleanup.append(self._stop_tasks)

        warden_tasks_to_start = [
            PeriodicalTask(
                "stat_tasks_starter__report_campaigns_not_spending_budget",
                lambda *a: tasks.not_spending_budget(),
            )
        ]

        self.warden_task_master = TaskMaster(
            server_url=config.WARDEN_URL, tasks=warden_tasks_to_start
        )

    async def _start_tasks(self, *args):
        loop = asyncio.get_event_loop()
        self.started_tasks = [loop.create_task(t) for t in self.tasks_to_start]

        await self.warden_task_master.run()

    async def _stop_tasks(self, *args):
        for task in self.started_tasks:
            task.cancel()
        self.started_tasks = []

        await self.warden_task_master.stop()

    @staticmethod
    def _init_sentry():
        sentry_dsn = config.SENTRY_DSN
        if not sentry_dsn:
            return

        kwargs = {"integrations": [AioHttpIntegration()]}
        if revision > 0:
            kwargs["release"] = f"r{revision}"

        sentry_sdk.init(sentry_dsn, **kwargs)
