"""Провайдер репутации Kaspersky OpenTIP."""

from __future__ import annotations

from contextlib import AbstractAsyncContextManager, asynccontextmanager
import logging
from typing import Any, AsyncIterator

import httpx

from ..iocs import IOCType
from .base import BaseProvider, FeatureValue

TOKEN_NAME = "kaspersky"

logger = logging.getLogger(__name__)


class KasperskyProvider(BaseProvider):
    """Выполняет запросы к API Kaspersky OpenTIP."""

    API_BASE = "https://opentip.kaspersky.com/api/v1"

    def __init__(self) -> None:
        """Создать провайдера Kaspersky с обязательным API-токеном."""
        super().__init__("kaspersky", requires_token=True, token_name=TOKEN_NAME)

    def get_context(
        self, token: str | None = None
    ) -> AbstractAsyncContextManager[httpx.AsyncClient]:
        """Инициализировать HTTP-клиент с авторизационным заголовком."""
        if not token:
            raise ValueError("Для Kaspersky требуется API-токен")

        headers = {"x-api-key": token, "Accept": "application/json"}
        logger.debug(
            "Создаём HTTP-клиент для Kaspersky OpenTIP: прокси=%s, таймаут=%.2f",
            self.http_proxy or "не используется",
            self.http_timeout,
        )

        @asynccontextmanager
        async def _client() -> AsyncIterator[httpx.AsyncClient]:
            client_kwargs = self.build_http_client_kwargs(
                base_url=self.API_BASE,
                headers=headers,
            )
            async with httpx.AsyncClient(**client_kwargs) as client:
                yield client

        return _client()

    async def fetch(self, indicator: IOCType, context: Any) -> dict[str, Any] | bool:
        """Запросить сведения об IOC в Kaspersky OpenTIP."""

        category = getattr(indicator, "category", None)

        if category == "ip":
            logger.info(
                "Проверка IP-адресов через Kaspersky OpenTIP отключена, пропускаем %s",
                indicator.value,
            )
            return False

        endpoint_map = {
            "hash": "search/hash",
            "ip": "search/ip",
            "url": "search/url",
            "domain": "search/domain",
        }

        endpoint = endpoint_map.get(category)

        if endpoint is None:
            logger.info(
                "Kaspersky OpenTIP не поддерживает индикатор %s (%s)",
                indicator.value,
                getattr(indicator, "category", "unknown"),
            )
            return False

        logger.info(
            "Запрашиваем Kaspersky OpenTIP для %s (%s)",
            indicator.value,
            getattr(indicator, "category", "unknown"),
        )

        try:
            response = await context.get(endpoint, params={"request": indicator.value})
            response.raise_for_status()
            return response.json()
        except httpx.HTTPStatusError as exc:
            if exc.response is not None and exc.response.status_code == 404:
                logger.info(
                    "Kaspersky OpenTIP вернул 404 для %s, возвращаем пустой ответ",
                    indicator.value,
                )
                return {}

            logger.exception(
                "Не удалось получить данные Kaspersky OpenTIP для %s: %s",
                indicator.value,
                exc,
            )
            return False
        except Exception as exc:
            logger.exception(
                "Не удалось получить данные Kaspersky OpenTIP для %s: %s",
                indicator.value,
                exc,
            )
            return False

    def build_features(
        self,
        payload: Any,
        *,
        indicator: IOCType | None = None,
    ) -> dict[str, FeatureValue]:
        """Рассчитать фичи по ответу Kaspersky OpenTIP."""
        from math import log1p

        general_info = payload.get("DomainGeneralInfo", {})

        urls_count = general_info.get("UrlsCount", 0)
        files_count = general_info.get("FilesCount", 0)
        hits_count = general_info.get("HitsCount", 0)
        ipv4_count = general_info.get("Ipv4Count")

        features = {
            "kasp_log_urls": log1p(urls_count),
            "kasp_log_files": log1p(files_count),
            "kasp_log_hits": log1p(hits_count),
            "kasp_ipv4_count": ipv4_count,
            "kasp_zone": str(payload.get("Zone")),
        }

        category = getattr(indicator, "category", "domain")
        if category in {"domain", "ip"}:
            features.pop("kasp_zone", None)

        return features
