"""Domain router for free-text citation queries.

Analyzes query text for domain-specific keywords and routes to the most
relevant academic data source.
"""

from __future__ import annotations

import re

from alice_cli.cite.models import IdentifierType

# ── Domain keyword mappings ───────────────────────────────────────────────────
# Each entry maps an IdentifierType to a set of lowercase keywords/phrases.

_DOMAIN_KEYWORDS: dict[IdentifierType, list[str]] = {
    IdentifierType.PMID: [
        "patient",
        "clinical",
        "disease",
        "drug",
        "therapy",
        "medical",
        "biomedical",
        "pathology",
        "diagnosis",
        "treatment",
        "epidemiology",
        "pharmacology",
        "surgery",
        "oncology",
        "cardiology",
        "neurology",
        "psychiatry",
        "radiology",
        "pediatrics",
        "immunology",
        "vaccine",
        "genome",
        "protein",
        "cell biology",
        "molecular biology",
        "pubmed",
    ],
    IdentifierType.ARXIV: [
        "machine learning",
        "deep learning",
        "neural network",
        "computer science",
        "algorithm",
        "nlp",
        "natural language processing",
        "computer vision",
        "reinforcement learning",
        "transformer",
        "convolutional",
        "recurrent",
        "generative",
        "adversarial",
        "artificial intelligence",
        "arxiv",
        "preprint",
    ],
    IdentifierType.GITHUB: [
        "github",
        "repository",
        "open source",
        "software",
        "library",
        "framework",
        "package",
        "source code",
        "codebase",
    ],
    IdentifierType.ISBN: [
        "book",
        "textbook",
        "isbn",
        "edition",
        "chapter",
        "monograph",
        "handbook",
        "encyclopedia",
    ],
    IdentifierType.ZENODO: [
        "dataset",
        "zenodo",
        "data repository",
        "research data",
    ],
    IdentifierType.SEMANTIC_SCHOLAR: [
        "semantic scholar",
        "s2",
        "citation graph",
        "citation network",
        "influence",
        "impact factor",
        "highly cited",
        "bibliometrics",
    ],
    IdentifierType.DBLP: [
        "dblp",
        "computer science bibliography",
        "proceedings",
        "conference paper",
        "workshop paper",
        "software engineering",
        "programming language",
        "database systems",
        "distributed systems",
        "operating systems",
        "compiler",
        "formal methods",
    ],
    IdentifierType.ORCID: [
        "orcid",
        "researcher id",
        "author profile",
        "author identifier",
    ],
}

# Pre-compile a single regex per domain for efficient matching.
# We use word-boundary matching for single words and plain substring
# matching for multi-word phrases.
_DOMAIN_PATTERNS: list[tuple[IdentifierType, re.Pattern[str]]] = []

for _id_type, _keywords in _DOMAIN_KEYWORDS.items():
    # Build alternation: multi-word phrases first (longer matches), then single words with \b
    parts: list[str] = []
    for kw in sorted(_keywords, key=len, reverse=True):
        escaped = re.escape(kw)
        if " " in kw:
            # Multi-word phrase: match as-is (spaces already in text)
            parts.append(escaped)
        else:
            # Single word: use word boundaries
            parts.append(rf"\b{escaped}\b")
    pattern = re.compile("|".join(parts), re.IGNORECASE)
    _DOMAIN_PATTERNS.append((_id_type, pattern))


def route_query(query: str) -> IdentifierType | None:
    """Analyze free-text query for domain keywords and return the best source type.

    Returns the ``IdentifierType`` whose keywords appear most frequently in
    *query*, or ``None`` when no domain keywords match (falls back to CrossRef).

    Matching is case-insensitive.
    """
    if not query or not query.strip():
        return None

    best_type: IdentifierType | None = None
    best_count = 0

    for id_type, pattern in _DOMAIN_PATTERNS:
        matches = pattern.findall(query)
        count = len(matches)
        if count > best_count:
            best_count = count
            best_type = id_type

    return best_type
