"""Simple voice command parser for Issue #409.

Commands supported:
- nav.follow_me: "follow me", "come with me", "follow along"
- nav.stop: "stop", "halt", "freeze", "don't move"
- nav.come_here: "come here", "come to me", "approach me"
- nav.go_home: "go home", "return home", "go to base"
- system.battery: "battery", "battery status", "how's the battery"
- nav.spin: "spin", "turn around", "spin around"
- system.quiet_mode: "quiet mode", "be quiet", "quiet"
"""

from __future__ import annotations

import re
from dataclasses import dataclass
from difflib import SequenceMatcher
from typing import Dict, Optional


@dataclass
class ParsedVoiceCommand:
    """Result of voice command parsing."""
    intent: str                     # e.g. "nav.follow_me"
    confidence: float               # 0.0-1.0
    raw_text: str                   # Normalized input


# Text normalization
_STRIP_PUNCT = re.compile(r"[^\w\s'-]")
_MULTI_SPACE = re.compile(r"\s+")


def _normalize(text: str) -> str:
    """Lowercase, strip punctuation, collapse whitespace."""
    t = text.lower()
    t = _STRIP_PUNCT.sub(" ", t)
    t = _MULTI_SPACE.sub(" ", t)
    return t.strip()


# Simple keyword-based command definitions
_COMMANDS: Dict[str, Dict[str, list]] = {
    "nav.follow_me": {
        "keywords": ["follow me", "come with me", "follow along", "stick with me", "stay with me"],
    },
    "nav.stop": {
        "keywords": ["stop", "halt", "freeze", "don't move", "stop moving"],
    },
    "nav.come_here": {
        "keywords": ["come here", "come to me", "approach me", "get here"],
    },
    "nav.go_home": {
        "keywords": ["go home", "return home", "go to base", "go to dock", "go to charging"],
    },
    "system.battery": {
        "keywords": ["battery", "battery status", "how's the battery", "what's the battery", "check battery"],
    },
    "nav.spin": {
        "keywords": ["spin", "turn around", "spin around", "rotate", "do a spin"],
    },
    "system.quiet_mode": {
        "keywords": ["quiet mode", "be quiet", "quiet", "silence", "mute"],
    },
}


def _fuzzy_match(text: str, patterns: list, threshold: float = 0.75) -> Optional[float]:
    """Fuzzy match text against a list of patterns.

    Returns confidence score (0.0-1.0) if above threshold, else None.
    """
    best_score = 0.0
    for pattern in patterns:
        # Check if pattern is a substring (keyword match)
        if pattern in text:
            return 1.0  # Exact keyword match

        # Fuzzy matching
        ratio = SequenceMatcher(None, text, pattern).ratio()
        best_score = max(best_score, ratio)

    return best_score if best_score >= threshold else None


def parse(text: str) -> ParsedVoiceCommand:
    """Parse voice command text and return ParsedVoiceCommand.

    Tries exact keyword matching first, then fuzzy matching.
    Returns fallback intent with confidence=0.0 if no match.
    """
    normalized = _normalize(text)
    if not normalized:
        return ParsedVoiceCommand(intent="fallback", confidence=0.0, raw_text=text)

    best_intent = "fallback"
    best_confidence = 0.0

    # Try exact keyword match first
    for intent, cmd_def in _COMMANDS.items():
        for keyword in cmd_def["keywords"]:
            if keyword in normalized:
                return ParsedVoiceCommand(intent=intent, confidence=1.0, raw_text=normalized)

    # Fall back to fuzzy matching
    for intent, cmd_def in _COMMANDS.items():
        conf = _fuzzy_match(normalized, cmd_def["keywords"], threshold=0.70)
        if conf and conf > best_confidence:
            best_intent = intent
            best_confidence = conf

    return ParsedVoiceCommand(
        intent=best_intent,
        confidence=best_confidence,
        raw_text=normalized,
    )
