"""
Intent Router - Voice Command Classification
Routes detected intents to appropriate handlers

Supports all use case groups:
1. Kurze Notizen (Autofahrt)
2. Arbeitsblatt-Generierung (Zug)
3. Situatives Arbeiten (Schule)
4. Canvas-Editor
5. Korrektur & RAG-Assistenz
6. Follow-up über Tage
"""
import structlog
import re
from typing import Optional, List, Dict, Any
from dataclasses import dataclass

from config import settings
from models.task import TaskType
from models.session import TranscriptMessage

logger = structlog.get_logger(__name__)


@dataclass
class DetectedIntent:
    """Detected intent with confidence and parameters."""
    type: TaskType
    confidence: float
    parameters: Dict[str, Any]
    is_actionable: bool


# Pattern-based intent detection rules
INTENT_PATTERNS = {
    # Gruppe 1: Kurze Notizen
    TaskType.STUDENT_OBSERVATION: [
        r"notiz\s+zu\s+(\w+)",
        r"beobachtung\s+(\w+)",
        r"(\w+)\s+hat\s+(gestoert|gestört)",
        r"(\w+)\s+braucht",
    ],
    TaskType.REMINDER: [
        r"erinner\s+mich",
        r"morgen\s+(\d+:\d+)",
        r"reminder",
        r"nicht\s+vergessen",
    ],
    TaskType.HOMEWORK_CHECK: [
        r"hausaufgabe\s+kontrollieren",
        r"(\w+)\s+mathe\s+hausaufgabe",
        r"ha\s+check",
    ],
    TaskType.CONFERENCE_TOPIC: [
        r"thema\s+(lehrerkonferenz|konferenz)",
        r"fuer\s+die\s+konferenz",
        r"konferenzthema",
    ],
    TaskType.CORRECTION_NOTE: [
        r"aufgabe\s+(\d+)",
        r"haeufiger\s+fehler",
        r"naechste\s+stunde\s+erklaeren",
        r"korrekturnotiz",
    ],

    # Gruppe 2: Arbeitsblatt-Generierung
    TaskType.WORKSHEET_GENERATE: [
        r"arbeitsblatt\s+(erstellen|machen|generieren)",
        r"nimm\s+vokabeln",
        r"mach\s+(\d+)\s+lueckentexte",
        r"uebungsblatt",
    ],
    TaskType.WORKSHEET_DIFFERENTIATE: [
        r"differenzierung",
        r"zwei\s+schwierigkeitsstufen",
        r"basis\s+und\s+plus",
        r"leichtere\s+version",
    ],

    # Gruppe 3: Situatives Arbeiten
    TaskType.QUICK_ACTIVITY: [
        r"(\d+)\s+minuten\s+einstieg",
        r"schnelle\s+aktivitaet",
        r"warming\s*up",
        r"einstiegsaufgabe",
    ],
    TaskType.QUIZ_GENERATE: [
        r"vokabeltest",
        r"quiz\s+(erstellen|generieren)",
        r"(\d+)-minuten\s+test",
        r"kurzer\s+test",
    ],
    TaskType.PARENT_LETTER: [
        r"elternbrief\s+wegen",
        r"elternbrief",
        r"brief\s+an\s+eltern",
        r"wegen\s+wiederholter?\s+(stoerungen|störungen)",
        r"wegen\s+(stoerungen|störungen)",
        r"mitteilung\s+an\s+eltern",
    ],
    TaskType.CLASS_MESSAGE: [
        r"nachricht\s+an\s+(\d+\w+)",
        r"klassen\s*nachricht",
        r"info\s+an\s+die\s+klasse",
    ],

    # Gruppe 4: Canvas-Editor
    TaskType.CANVAS_EDIT: [
        r"ueberschriften?\s+(groesser|kleiner|größer)",
        r"bild\s+(\d+)\s+(nach|auf)",
        r"pfeil\s+(von|auf)",
        r"kasten\s+(hinzufuegen|einfügen)",
    ],
    TaskType.CANVAS_LAYOUT: [
        r"auf\s+eine\s+seite",
        r"drucklayout\s+a4",
        r"layout\s+(aendern|ändern)",
        r"alles\s+auf\s+a4",
    ],

    # Gruppe 5: Korrektur & RAG
    TaskType.OPERATOR_CHECKLIST: [
        r"operatoren[-\s]*checkliste",
        r"welche\s+operatoren",
        r"operatoren\s+fuer\s+diese\s+aufgabe",
    ],
    TaskType.EH_PASSAGE: [
        r"erwartungshorizont",
        r"eh\s*passage",
        r"was\s+steht\s+im\s+eh",
    ],
    TaskType.FEEDBACK_SUGGEST: [
        r"feedback\s*(vorschlag|vorschlagen)",
        r"wie\s+formuliere\s+ich",
        r"rueckmeldung\s+geben",
    ],

    # Gruppe 6: Follow-up
    TaskType.REMINDER_SCHEDULE: [
        r"erinner\s+mich\s+morgen",
        r"in\s+(\d+)\s+(stunden|tagen)",
        r"naechste\s+woche",
    ],
    TaskType.TASK_SUMMARY: [
        r"offenen?\s+(aufgaben|tasks)",
        r"was\s+steht\s+noch\s+an",
        r"zusammenfassung",
        r"fasse.+zusammen",
        r"diese[rn]?\s+woche",
    ],
}


class IntentRouter:
    """
    Routes voice commands to appropriate task types.

    Uses a combination of:
    1. Pattern matching for common phrases
    2. LLM-based classification for complex queries
    3. Context from previous messages for disambiguation
    """

    def __init__(self):
        self._compiled_patterns: Dict[TaskType, List[re.Pattern]] = {}
        self._compile_patterns()

    def _compile_patterns(self):
        """Pre-compile regex patterns for performance."""
        for task_type, patterns in INTENT_PATTERNS.items():
            self._compiled_patterns[task_type] = [
                re.compile(pattern, re.IGNORECASE | re.UNICODE)
                for pattern in patterns
            ]

    async def detect_intent(
        self,
        text: str,
        context: List[TranscriptMessage] = None,
    ) -> Optional[DetectedIntent]:
        """
        Detect intent from text with optional context.

        Args:
            text: Input text (transcript)
            context: Previous messages for disambiguation

        Returns:
            DetectedIntent or None if no clear intent
        """
        # Normalize text
        normalized = self._normalize_text(text)

        # Try pattern matching first
        pattern_result = self._pattern_match(normalized)
        if pattern_result and pattern_result.confidence > 0.6:
            logger.info(
                "Intent detected via pattern",
                type=pattern_result.type.value,
                confidence=pattern_result.confidence,
            )
            return pattern_result

        # Fall back to LLM classification
        if settings.fallback_llm_provider != "none":
            llm_result = await self._llm_classify(normalized, context)
            if llm_result and llm_result.confidence > 0.5:
                logger.info(
                    "Intent detected via LLM",
                    type=llm_result.type.value,
                    confidence=llm_result.confidence,
                )
                return llm_result

        # Check for context-based disambiguation
        if context:
            context_result = self._context_disambiguate(normalized, context)
            if context_result:
                logger.info(
                    "Intent detected via context",
                    type=context_result.type.value,
                )
                return context_result

        logger.debug("No intent detected", text=text[:50])
        return None

    def _normalize_text(self, text: str) -> str:
        """Normalize text for matching."""
        # Convert umlauts
        text = text.lower()
        text = text.replace("ä", "ae").replace("ö", "oe").replace("ü", "ue")
        text = text.replace("ß", "ss")
        # Remove extra whitespace
        text = " ".join(text.split())
        return text

    def _pattern_match(self, text: str) -> Optional[DetectedIntent]:
        """Match text against known patterns."""
        best_match = None
        best_confidence = 0.0

        for task_type, patterns in self._compiled_patterns.items():
            for pattern in patterns:
                match = pattern.search(text)
                if match:
                    # Calculate confidence based on match quality
                    match_ratio = len(match.group()) / len(text)
                    confidence = min(0.95, 0.6 + match_ratio * 0.4)

                    if confidence > best_confidence:
                        # Extract parameters from groups
                        parameters = self._extract_parameters(task_type, match, text)

                        best_match = DetectedIntent(
                            type=task_type,
                            confidence=confidence,
                            parameters=parameters,
                            is_actionable=self._is_actionable(task_type),
                        )
                        best_confidence = confidence

        return best_match

    def _extract_parameters(
        self,
        task_type: TaskType,
        match: re.Match,
        full_text: str,
    ) -> Dict[str, Any]:
        """Extract parameters from regex match."""
        params = {}

        # Extract named groups or positional groups
        if match.groups():
            groups = match.groups()

            # Task-specific parameter extraction
            if task_type == TaskType.STUDENT_OBSERVATION:
                params["student_name"] = groups[0] if groups else None

            elif task_type == TaskType.HOMEWORK_CHECK:
                params["subject"] = "mathe" if "mathe" in full_text else None

            elif task_type == TaskType.QUICK_ACTIVITY:
                params["duration_minutes"] = int(groups[0]) if groups else 10

            elif task_type == TaskType.QUIZ_GENERATE:
                params["duration_minutes"] = int(groups[0]) if groups and groups[0].isdigit() else 10

            elif task_type == TaskType.CLASS_MESSAGE:
                params["class_name"] = groups[0] if groups else None

        # Extract time references
        time_match = re.search(r"(\d{1,2}):?(\d{2})?", full_text)
        if time_match:
            params["time"] = time_match.group()

        # Extract content after colon
        colon_match = re.search(r":\s*(.+)$", full_text)
        if colon_match:
            params["content"] = colon_match.group(1).strip()

        return params

    def _is_actionable(self, task_type: TaskType) -> bool:
        """Check if intent type creates an actionable task."""
        # All task types are actionable except queries
        query_types = [
            TaskType.OPERATOR_CHECKLIST,
            TaskType.EH_PASSAGE,
            TaskType.TASK_SUMMARY,
        ]
        return task_type not in query_types

    async def _llm_classify(
        self,
        text: str,
        context: List[TranscriptMessage] = None,
    ) -> Optional[DetectedIntent]:
        """Use LLM for intent classification."""
        from services.fallback_llm_client import FallbackLLMClient

        llm = FallbackLLMClient()
        result = await llm.detect_intent(text)

        if result.get("type") == "unknown":
            return None

        try:
            task_type = TaskType(result["type"])
            return DetectedIntent(
                type=task_type,
                confidence=result.get("confidence", 0.5),
                parameters=result.get("parameters", {}),
                is_actionable=result.get("is_actionable", True),
            )
        except ValueError:
            logger.warning("Unknown task type from LLM", type=result.get("type"))
            return None

    def _context_disambiguate(
        self,
        text: str,
        context: List[TranscriptMessage],
    ) -> Optional[DetectedIntent]:
        """Disambiguate intent using conversation context."""
        if not context:
            return None

        # Look for continuation patterns
        continuation_words = ["ja", "genau", "richtig", "okay", "mach das", "bitte"]

        if any(word in text.lower() for word in continuation_words):
            # Find the last assistant message with a suggestion
            for msg in reversed(context):
                if msg.role == "assistant" and msg.intent:
                    try:
                        return DetectedIntent(
                            type=TaskType(msg.intent),
                            confidence=0.6,
                            parameters={},
                            is_actionable=True,
                        )
                    except ValueError:
                        pass

        return None
