import asyncio
import logging

from typing import Optional, Dict

from saas.library.python.logbroker import LogbrokerEndpoint
from saas.library.python.logbroker.cluster_api.client import ClustersInfo, ClusterInfo
from saas.tools.devops.lb_dc_checker.dc_checker.checkers.common import LogbrokerFactory


class LogbrokerClusterChecker:
    _CHECK_INTERVAL_SECONDS = 30
    _ERROR_SLEEP_SECONDS = 10

    _TARGET_ENDPOINTS = [
        LogbrokerEndpoint('logbroker.yandex.net', 2135)
    ]

    def __init__(self) -> None:
        self._endpoint_to_check_result: Dict[LogbrokerEndpoint, ClustersInfo] = {}

    def get_last_check_result(self, dc: str, endpoint: LogbrokerEndpoint) -> Optional[ClusterInfo]:
        check_result = self._endpoint_to_check_result.get(endpoint)
        if not check_result:
            return None

        return check_result.dc_to_cluster_info.get(dc)

    async def run(self) -> None:
        while True:
            coro_arr = []
            for endpoint in self._TARGET_ENDPOINTS:
                client = LogbrokerFactory.create_cluster_info_client(endpoint)
                coro_arr.append(client.get_clusters_read_info())

            try:
                result = await asyncio.gather(*coro_arr)
            except asyncio.CancelledError:
                raise
            except Exception:
                logging.exception('Unable to get cluster info, retrying in %d seconds', self._ERROR_SLEEP_SECONDS)
            else:
                for endpoint, curr_result in zip(self._TARGET_ENDPOINTS, result):
                    result_changed = curr_result != self._endpoint_to_check_result.get(endpoint)

                    logging.log(
                        logging.INFO if not result_changed else logging.WARNING,
                        'Updated cluster info for %s: changed=%s, info=%s',
                        endpoint.host,
                        curr_result != self._endpoint_to_check_result.get(endpoint),
                        curr_result
                    )

                    self._endpoint_to_check_result[endpoint] = curr_result

            await asyncio.sleep(self._CHECK_INTERVAL_SECONDS)
