"""Rules-first answer level classification with optional LLM override via env."""

from __future__ import annotations

import os
import re
from typing import Any

ANSWER_LEVELS = frozenset(
    {
        "conceptual",
        "architectural",
        "practical",
        "technical",
        "factual",
        "troubleshooting",
    }
)

_ARCHITECTURAL_PATTERNS = (
    r"\bархитектур",
    r"\barchitecture\b",
    r"\bdesign pattern",
    r"\bмикросервис",
    r"\bmicroservice",
    r"\bсистемн(ая|ой)\s+архитектур",
    r"\bhow\s+should\s+.+\s+be\s+structured",
    r"\bкак\s+спроектировать",
    r"\bкак\s+построить\s+систем",
)

_TROUBLESHOOTING_PATTERNS = (
    r"\bне\s+работает",
    r"\bошибк",
    r"\berror\b",
    r"\bfix\b",
    r"\bdebug\b",
    r"\btroubleshoot",
    r"\bпочему\s+падает",
    r"\bне\s+запускается",
    r"\bне\s+открывается",
)

_TECHNICAL_PATTERNS = (
    r"\bapi\b",
    r"\bendpoint\b",
    r"\bsql\b",
    r"\bregex\b",
    r"\bкод\b",
    r"\bcode\b",
    r"\bфункци",
    r"\bclass\b",
    r"\bметод",
    r"\bконфиг",
    r"\bconfig\b",
)

_PRACTICAL_PATTERNS = (
    r"\bкак\s+сделать",
    r"\bhow\s+to\b",
    r"\bstep\s+by\s+step",
    r"\bпошагов",
    r"\binstall\b",
    r"\bустанов",
    r"\bнастро",
    r"\bsetup\b",
)

_CONCEPTUAL_PATTERNS = (
    r"\bчто\s+такое",
    r"\bwhat\s+is\b",
    r"\bexplain\b",
    r"\bобъясни",
    r"\bconcept\b",
    r"\bконцепц",
    r"\bпринцип",
)

_FACTUAL_PATTERNS = (
    r"\bкогда\b",
    r"\bwhen\b",
    r"\bсколько\b",
    r"\bhow\s+many\b",
    r"\bкто\b",
    r"\bwho\b",
    r"\bгде\b",
    r"\bwhere\b",
    r"\b\d{4}\b",
)


def _matches_any(text: str, patterns: tuple[str, ...]) -> bool:
    return any(re.search(pattern, text, flags=re.IGNORECASE) for pattern in patterns)


def classify_answer_level_rules(question: str) -> str:
    text = str(question or "").strip().lower()
    if not text:
        return "factual"

    if _matches_any(text, _TROUBLESHOOTING_PATTERNS):
        return "troubleshooting"
    if _matches_any(text, _ARCHITECTURAL_PATTERNS):
        return "architectural"
    if _matches_any(text, _TECHNICAL_PATTERNS):
        return "technical"
    if _matches_any(text, _PRACTICAL_PATTERNS):
        return "practical"
    if _matches_any(text, _CONCEPTUAL_PATTERNS):
        return "conceptual"
    if _matches_any(text, _FACTUAL_PATTERNS):
        return "factual"
    return "conceptual"


def _classify_with_llm(question: str) -> str | None:
    if os.environ.get("IUVE_ANSWER_LEVEL_LLM", "").strip().lower() not in {"1", "true", "yes", "on"}:
        return None
    try:
        from app.services.llm_service import llm_service  # type: ignore

        prompt = (
            "Classify the user question into exactly one level: "
            "conceptual, architectural, practical, technical, factual, troubleshooting. "
            "Reply with the single word only.\n\nQuestion: "
            + str(question or "")
        )
        raw = str(llm_service.chat(prompt, []) or "").strip().lower()
        for level in ANSWER_LEVELS:
            if level in raw:
                return level
    except Exception:
        return None
    return None


def classify_answer_level(question: str) -> str:
    llm_level = _classify_with_llm(question)
    if llm_level in ANSWER_LEVELS:
        return llm_level
    return classify_answer_level_rules(question)


def detect_level_mismatch(question: str, answer: str, declared_level: str = "") -> bool:
    expected = str(declared_level or classify_answer_level(question) or "").strip()
    if expected not in ANSWER_LEVELS:
        return False
    body = str(answer or "").strip().lower()
    if not body:
        return False

    mismatch_signals: dict[str, tuple[str, ...]] = {
        "factual": (r"\bstep\s+\d", r"\bшаг\s+\d", r"\bархитектур"),
        "architectural": (r"^\d{4}$",),
        "troubleshooting": (r"\bwhat\s+is\b", r"\bчто\s+такое\b"),
    }
    patterns = mismatch_signals.get(expected, ())
    return any(re.search(pattern, body, flags=re.IGNORECASE) for pattern in patterns)
