"""Минимальное представление хеш-индикаторов и шаблоны их поиска."""

from __future__ import annotations

import logging
import re
from dataclasses import dataclass, field
from typing import Any, FrozenSet, Mapping

from .analysis import IndicatorAnalysisMixin, build_kaspersky_zone_verdict
from .patterns import PatternDefinition
from .reason_texts import (
    KASPERSKY_HASH_BLOCK_REASON,
    KASPERSKY_HASH_MONITOR_REASON,
    KASPERSKY_HASH_OK_REASON,
)
from ..tags import build_malwarebazaar_tag

_MD5_PATTERN = re.compile(r"\b([a-f0-9]{32})\b", re.IGNORECASE)
_SHA1_PATTERN = re.compile(r"\b([a-f0-9]{40})\b", re.IGNORECASE)
_SHA256_PATTERN = re.compile(r"\b([a-f0-9]{64})\b", re.IGNORECASE)

_logger = logging.getLogger(__name__)


@dataclass(frozen=True)
class HashIndicator(IndicatorAnalysisMixin):
    """Индикатор файла по хешу."""

    value: str
    kinds: FrozenSet[str] = field(default_factory=frozenset)
    algorithm: str = "generic"

    @property
    def category(self) -> str:
        """Категория индикатора."""

        return "hash"

    def pre_analysis(self) -> dict[str, Any]:
        """Отсутствие быстрых правил перед запросами к провайдерам."""

        _logger.info(
            "Для хеша %s (%s) нет быстрых правил, продолжаем анализ через провайдеров",
            self.value,
            self.algorithm,
        )
        return {}

    def analysis(self, features: Mapping[str, Any] | None = None) -> dict[str, Any]:
        """Анализ хеша по зоне Kaspersky."""

        prepared_features = features or {}
        _logger.info(
            "Проверяем зону Kaspersky для хеша %s (%s)",
            self.value,
            self.algorithm,
        )

        verdict = build_kaspersky_zone_verdict(
            prepared_features,
            block_reason=KASPERSKY_HASH_BLOCK_REASON,
            monitor_reason=KASPERSKY_HASH_MONITOR_REASON,
            ok_reason=KASPERSKY_HASH_OK_REASON,
        )

        tags: list[dict[str, str]] = []
        malwarebazaar_features = prepared_features.get("malwarebazaar") or {}
        has_malwarebazaar_data = bool(malwarebazaar_features.get("malbazaar_has_response"))
        sample_sha256 = malwarebazaar_features.get("malbazaar_sha256")

        if has_malwarebazaar_data and sample_sha256:
            tags.append(build_malwarebazaar_tag(sample_sha256))

        return {
            "features": prepared_features,
            "status": "ok",
            "tags": tags,
            **verdict,
        }


def create_hash_indicator(
    value: str, kinds: FrozenSet[str], *, algorithm: str
) -> HashIndicator:
    """Создать хеш-индикатор с явным указанием алгоритма."""

    return HashIndicator(value=value, kinds=kinds, algorithm=algorithm)


def build_patterns() -> tuple[PatternDefinition, ...]:
    """Вернуть правила выделения хешей."""

    return (
        PatternDefinition(
            name="sha256",
            regex=_SHA256_PATTERN,
            factory=lambda value, kinds: create_hash_indicator(
                value=value, kinds=kinds, algorithm="sha256"
            ),
            kinds=frozenset({"hash", "sha256"}),
            normalize=str.lower,
        ),
        PatternDefinition(
            name="sha1",
            regex=_SHA1_PATTERN,
            factory=lambda value, kinds: create_hash_indicator(
                value=value, kinds=kinds, algorithm="sha1"
            ),
            kinds=frozenset({"hash", "sha1"}),
            normalize=str.lower,
        ),
        PatternDefinition(
            name="md5",
            regex=_MD5_PATTERN,
            factory=lambda value, kinds: create_hash_indicator(
                value=value, kinds=kinds, algorithm="md5"
            ),
            kinds=frozenset({"hash", "md5"}),
            normalize=str.lower,
        ),
    )
