from __future__ import annotations

import re

from app.models.intent import (
    INTENT_CONFIGS,
    IntentResult,
    QueryIntent,
)
from app.models.internal_retrieve import SourceType

HISTORICAL_SIGNALS = (
    "why",
    "when",
    "who changed",
    "history",
    "commit",
    "refactor",
    "last changed",
    "refactored",
)

CODE_LOOKUP_SIGNALS = (
    "where",
    "find",
    "defined",
    "function",
    "method",
    "class",
    "locate",
)

DOCUMENTATION_SIGNALS = (
    "docs",
    "readme",
    "document",
    "how to",
    "configure",
    "configuration",
)

ARCHITECTURE_SIGNALS = (
    "architecture",
    "pipeline",
    "overview",
    "flow",
    "diagram",
    "explain the system",
    "explain system",
    "how does",
    "triggered",
    "functionality",
    "functionalities",
    "features",
    "what does this repo",
    "what is this repo",
    "capabilities",
    "what can this repo",
    "main features",
)

SYMBOL_PATTERN = re.compile(
    r"`[^`]+`|\b[a-z_][a-z0-9_]*\(\)|\b[A-Z][a-z]+[A-Z][a-zA-Z0-9]*\b"
)

MATCH_CONFIDENCE = 0.85
GENERAL_CONFIDENCE = 0.5
MIXED_CONFIDENCE = 0.7


class IntentAnalyzer:
    """Tier-1 rule-based intent analyzer (HLD §5.3)."""

    def analyze(self, question: str) -> IntentResult:
        normalized = question.strip().lower()
        if not normalized:
            return self._result(QueryIntent.GENERAL, GENERAL_CONFIDENCE)

        scores: dict[QueryIntent, int] = {
            QueryIntent.HISTORICAL: self._count_signals(normalized, HISTORICAL_SIGNALS),
            QueryIntent.CODE_LOOKUP: self._count_signals(normalized, CODE_LOOKUP_SIGNALS),
            QueryIntent.DOCUMENTATION: self._count_signals(normalized, DOCUMENTATION_SIGNALS),
            QueryIntent.ARCHITECTURE: self._count_signals(normalized, ARCHITECTURE_SIGNALS),
        }

        if SYMBOL_PATTERN.search(question):
            scores[QueryIntent.CODE_LOOKUP] += 1

        matched = {intent: count for intent, count in scores.items() if count > 0}

        if not matched:
            return self._result(QueryIntent.GENERAL, GENERAL_CONFIDENCE)

        if len(matched) > 1:
            return self._result(QueryIntent.MIXED, MIXED_CONFIDENCE)

        intent = max(matched, key=lambda k: matched[k])
        return self._result(intent, MATCH_CONFIDENCE)

    def _count_signals(self, text: str, signals: tuple[str, ...]) -> int:
        count = 0
        for signal in signals:
            if " " in signal:
                if signal in text:
                    count += 1
                continue
            if re.search(rf"\b{re.escape(signal)}\b", text):
                count += 1
        return count

    def _result(self, intent: QueryIntent, confidence: float) -> IntentResult:
        config = INTENT_CONFIGS[intent]
        source_types_used: list[SourceType] = list(config.source_types or [])
        return IntentResult(
            type=intent,
            confidence=confidence,
            source_types_used=source_types_used,
        )
