import asyncio
import logging
from concurrent.futures.thread import ThreadPoolExecutor
from typing import Dict, Optional

from yt.wrapper import YtClient

from .timing import TimeDiff, async_time_diff


class AsyncYtClient:

    _yt_client: YtClient
    _thread_pool: ThreadPoolExecutor

    _google_counters_table: str

    def __init__(self, yt_token: str, google_counters_table: str):
        self._yt_client = YtClient(
            proxy="markov",
            token=yt_token,
            config={
                "dynamic_table_retries": {"count": 1, "enable": False},
                "proxy": {
                    "url": "markov",
                    "retries": {"enable": False},
                    "connect_timeout": 200,
                    "heavy_request_timeout": 200,
                },
            },
        )
        self._google_counters_table = google_counters_table

    def start(self):
        self._thread_pool = ThreadPoolExecutor(
            max_workers=1
        )  # yt_client is not thread-safe, so only 1

    def close(self):
        self._thread_pool.shutdown()

    @async_time_diff
    async def get_google_counters_for_permalink(self, permalink: int) -> Optional[Dict]:
        def _get_get_google_counters_for_permalink(
            yt_client: YtClient, permalink: int
        ) -> Optional[Dict]:

            try:
                result = list(
                    yt_client.select_rows(
                        f"counter_id, event_id, event_name FROM  "
                        f"[{self._google_counters_table}]"
                        f" WHERE permalink = {permalink}",
                        format="yson",
                    )
                )
                if result:
                    counters = {}
                    for row in result:
                        counters.setdefault(row["counter_id"], {}).update(
                            {row["event_name"]: row["event_id"]}
                        )
                    return [
                        {"id": id, "goals": goals} for id, goals in counters.items()
                    ]

            except Exception as e:
                logging.getLogger(__name__).error(
                    "Unable to obtain Google counters", exc_info=e
                )
                return None

        try:

            processing = asyncio.get_running_loop().run_in_executor(
                self._thread_pool,
                _get_get_google_counters_for_permalink,
                self._yt_client,
                permalink,
            )

            with TimeDiff("AsyncYtClient.processing"):
                await processing

            return processing.result()

        except Exception as e:
            logging.getLogger(__name__).error(
                "Unable to obtain Google counters", exc_info=e
            )
            return None
