"""Базовые определения провайдеров."""

from __future__ import annotations

from abc import ABC, abstractmethod
from contextlib import AbstractAsyncContextManager, asynccontextmanager
import logging
from typing import Any, Dict

from ..config import settings
from ..http_client import build_http_client_options
from ..iocs import IOCType

FeatureValue = bool | int | float | str | None

logger = logging.getLogger(__name__)


class BaseProvider(ABC):
    """Базовый класс провайдеров репутации."""

    name: str
    requires_token: bool
    token_name: str | None

    def __init__(
        self,
        name: str,
        *,
        requires_token: bool = False,
        token_name: str | None = None,
    ) -> None:
        self.name = name
        self.requires_token = requires_token
        if requires_token:
            self.token_name = token_name or name
        else:
            self.token_name = token_name

    def is_available(self) -> bool:
        """Проверить, может ли провайдер обрабатывать запросы."""

        return True

    @property
    def http_timeout(self) -> float:
        """Вернуть настроенный таймаут HTTP-клиента."""

        return settings.http_timeout

    @property
    def http_proxy(self) -> str | None:
        """Вернуть адрес прокси-сервера для HTTP-запросов."""

        return settings.http_proxy

    def build_http_client_kwargs(self, **overrides: Any) -> Dict[str, Any]:
        """Сформировать параметры для ``httpx.AsyncClient`` с учётом настроек."""

        return build_http_client_options(timeout=self.http_timeout, **overrides)

    def get_context(self, token: str | None = None) -> AbstractAsyncContextManager[Any]:
        """Вернуть асинхронный контекст-менеджер для API-вызовов."""

        @asynccontextmanager
        async def _null_context() -> Any:
            yield None

        return _null_context()

    @abstractmethod
    async def fetch(self, indicator: IOCType, context: Any) -> dict[str, Any]:
        """Получить сведения об IOC, используя ``context``."""

    def build_features(
        self,
        payload: Any,
        *,
        indicator: IOCType | None = None,
    ) -> dict[str, FeatureValue]:
        """Построить набор фичей на основе ``payload``.

        Базовая реализация возвращает пустой набор, поскольку конкретные
        провайдеры должны реализовать расчёт самостоятельно. Поведение безопасно
        и не приводит к выбросу исключений при отсутствии поддержки фичей.
        """

        indicator_value = getattr(indicator, "value", indicator)
        logger.debug(
            "Фичи для провайдера %s не реализованы, возвращаем пустой набор (индикатор=%s)",
            self.name,
            indicator_value,
        )
        return {}
