"""
DNA Patterns — библиотека известных архитектурных паттернов.

Каждый паттерн описывается именем, категорией и сигнальными словами,
которые ищутся в именах классов, функций и файлов проекта.
"""

from __future__ import annotations

from dataclasses import dataclass

from ..memory.store import KodaraIndex


@dataclass
class Pattern:
    name: str
    category: str
    keywords: list[str]


# ── Известные паттерны ────────────────────────────────────────────────────────

PATTERNS: list[Pattern] = [
    # Auth
    Pattern("JWT",          "Auth",     ["jwt", "token", "bearer"]),
    Pattern("Session",      "Auth",     ["session", "cookie"]),
    Pattern("OAuth",        "Auth",     ["oauth", "scope", "authorize"]),
    Pattern("API Key",      "Auth",     ["apikey", "api_key", "x-api-key"]),

    # Routing
    Pattern("Decorator",    "Routing",  ["route", "endpoint", "handler"]),
    Pattern("Config-based", "Routing",  ["urlconf", "urls", "router"]),
    Pattern("Middleware",   "Routing",  ["middleware", "interceptor"]),

    # Database
    Pattern("Repository",   "Database", ["repository", "repo"]),
    Pattern("ORM",          "Database", ["model", "queryset", "orm"]),
    Pattern("ActiveRecord", "Database", ["activerecord", "record"]),
    Pattern("QueryBuilder", "Database", ["querybuilder", "query_builder", "build_query"]),
    Pattern("Migration",    "Database", ["migration", "migrate", "alembic", "flyway"]),

    # Caching
    Pattern("Redis",        "Caching",  ["redis", "cache"]),
    Pattern("Memory",       "Caching",  ["lru_cache", "cached", "memoize", "memo"]),
    Pattern("CDN",          "Caching",  ["cdn", "cloudfront", "cloudflare"]),

    # Queue
    Pattern("Celery",       "Queue",    ["celery", "task", "worker"]),
    Pattern("RabbitMQ",     "Queue",    ["rabbitmq", "amqp", "pika"]),
    Pattern("Kafka",        "Queue",    ["kafka", "consumer", "producer"]),

    # Testing
    Pattern("Unit Tests",   "Testing",  ["unittest", "pytest", "test_", "_test"]),
    Pattern("Mocks",        "Testing",  ["mock", "stub", "fixture", "monkeypatch"]),
    Pattern("E2E",          "Testing",  ["e2e", "selenium", "playwright", "cypress"]),
]


# ── Детектор паттернов ────────────────────────────────────────────────────────

def detect_patterns(index: KodaraIndex) -> dict[str, list[str]]:
    """
    Сканирует индекс и возвращает обнаруженные паттерны по категориям.

    Алгоритм: ищет keywords (lowercase) в именах классов, функций и
    именах файлов/модулей по всем модулям индекса.

    Returns:
        dict[category → list[detected_pattern_names]]
        Пустые категории включены в результат (с пустыми списками).
    """
    # Собираем все "сигнальные токены" из индекса
    tokens: set[str] = set()
    for mod in index.modules.values():
        # Имя файла / путь
        path_lower = str(mod.get("path", "")).lower()
        module_lower = str(mod.get("module_name", "")).lower()
        tokens.add(path_lower)
        tokens.add(module_lower)

        # Классы
        for cls in mod.get("classes", []) or []:
            tokens.add(str(cls).lower())

        # Функции
        for fn in mod.get("functions", []) or []:
            tokens.add(str(fn).lower())

    # Все категории в результате (даже если пустые)
    all_categories: list[str] = list(dict.fromkeys(p.category for p in PATTERNS))
    result: dict[str, list[str]] = {cat: [] for cat in all_categories}

    # Проверяем каждый паттерн
    for pattern in PATTERNS:
        for kw in pattern.keywords:
            kw_lower = kw.lower()
            if any(kw_lower in tok for tok in tokens):
                if pattern.name not in result[pattern.category]:
                    result[pattern.category].append(pattern.name)
                break  # один совпавший keyword уже достаточен

    return result
