"""Voice routes — /voice/* and /voice/enhanced/* endpoints.

Provides NLU intent detection, TTS control, the full voice-to-action
pipeline (detect intent → execute → optionally speak), the voice
button UI page, and voice settings customisation.
"""

import asyncio
import json
import logging
from pathlib import Path

from fastapi import APIRouter, Form, Request
from fastapi.responses import HTMLResponse

from dashboard.templating import templates
from integrations.voice.nlu import detect_intent, extract_command
from timmy.agent import create_timmy

# ── Voice settings persistence ───────────────────────────────────────────────

_VOICE_SETTINGS_FILE = Path("data/voice_settings.json")
_DEFAULT_VOICE_SETTINGS: dict = {"rate": 175, "volume": 0.9, "voice_id": ""}


def _load_voice_settings() -> dict:
    """Read persisted voice settings from disk; return defaults on any error."""
    try:
        if _VOICE_SETTINGS_FILE.exists():
            return json.loads(_VOICE_SETTINGS_FILE.read_text())
    except Exception as exc:
        logger.warning("Failed to load voice settings: %s", exc)
    return dict(_DEFAULT_VOICE_SETTINGS)


def _save_voice_settings(data: dict) -> None:
    """Persist voice settings to disk; log and continue on any error."""
    try:
        _VOICE_SETTINGS_FILE.parent.mkdir(parents=True, exist_ok=True)
        _VOICE_SETTINGS_FILE.write_text(json.dumps(data))
    except Exception as exc:
        logger.warning("Failed to save voice settings: %s", exc)


logger = logging.getLogger(__name__)

router = APIRouter(prefix="/voice", tags=["voice"])


@router.post("/nlu")
async def nlu_detect(text: str = Form(...)):
    """Detect intent from a text utterance."""
    intent = detect_intent(text)
    command = extract_command(text)
    return {
        "intent": intent.name,
        "confidence": intent.confidence,
        "entities": intent.entities,
        "command": command,
        "raw_text": intent.raw_text,
    }


@router.get("/tts/status")
async def tts_status():
    """Check TTS engine availability."""
    try:
        from timmy_serve.voice_tts import voice_tts

        return {
            "available": voice_tts.available,
            "voices": voice_tts.get_voices() if voice_tts.available else [],
        }
    except Exception as exc:
        logger.debug("Voice config error: %s", exc)
        return {"available": False, "voices": []}


@router.post("/tts/speak")
async def tts_speak(text: str = Form(...)):
    """Speak text aloud via TTS."""
    try:
        from timmy_serve.voice_tts import voice_tts

        if not voice_tts.available:
            return {"spoken": False, "reason": "TTS engine not available"}
        voice_tts.speak(text)
        return {"spoken": True, "text": text}
    except Exception as exc:
        logger.exception("TTS speak failed")
        return {"spoken": False, "reason": str(exc)}


# ── Voice button page ────────────────────────────────────────────────────


@router.get("/button", response_class=HTMLResponse)
async def voice_button_page(request: Request):
    """Render the voice button UI."""
    return templates.TemplateResponse(request, "voice_button.html")


@router.post("/command")
async def voice_command(text: str = Form(...)):
    """Process a voice command (used by voice_button.html).

    Wraps the enhanced pipeline and returns the result in the format
    the voice button template expects.
    """
    result = await process_voice_input(text=text, speak_response=False)
    return {
        "command": {
            "intent": result["intent"],
            "response": result["response"] or result.get("error", "No response"),
        }
    }


# ── Enhanced voice pipeline ──────────────────────────────────────────────


@router.post("/enhanced/process")
async def process_voice_input(
    text: str = Form(...),
    speak_response: bool = Form(False),
):
    """Process a voice input: detect intent -> execute -> optionally speak.

    This is the main entry point for voice-driven interaction with Timmy.
    """
    intent = detect_intent(text)
    response_text = None
    error = None

    try:
        if intent.name == "status":
            response_text = "Agent is operational and running locally. All systems nominal."

        elif intent.name == "help":
            response_text = (
                "Available commands: chat with me, check status, "
                "manage the swarm, create tasks, or adjust voice settings. "
                "Everything runs locally — no cloud, no permission needed."
            )

        elif intent.name == "swarm":
            response_text = "Swarm module is not currently active."

        elif intent.name == "voice":
            response_text = "Voice settings acknowledged. TTS is available for spoken responses."

        elif intent.name == "code":
            response_text = "Self-modification module is not currently active."

        else:
            # Default: chat with Timmy
            agent = create_timmy()
            run = agent.run(text, stream=False)
            response_text = run.content if hasattr(run, "content") else str(run)

    except Exception as exc:
        error = f"Processing failed: {exc}"
        logger.error("Voice processing error: %s", exc)

    # Optionally speak the response
    if speak_response and response_text:
        try:
            from timmy_serve.voice_tts import voice_tts

            if voice_tts.available:
                voice_tts.speak(response_text)
        except Exception as exc:
            logger.debug("Voice TTS error: %s", exc)
            pass

    return {
        "intent": intent.name,
        "confidence": intent.confidence,
        "response": response_text,
        "error": error,
        "spoken": speak_response and response_text is not None,
    }


# ── Voice settings UI ────────────────────────────────────────────────────────


@router.get("/settings", response_class=HTMLResponse)
async def voice_settings_page(request: Request):
    """Render the voice customisation settings page."""
    current = await asyncio.to_thread(_load_voice_settings)
    voices: list[dict] = []
    try:
        from timmy_serve.voice_tts import voice_tts

        if voice_tts.available:
            voices = await asyncio.to_thread(voice_tts.get_voices)
    except Exception as exc:
        logger.debug("Voice settings page: TTS not available — %s", exc)
    return templates.TemplateResponse(
        request,
        "voice_settings.html",
        {"settings": current, "voices": voices},
    )


@router.get("/settings/data")
async def voice_settings_data():
    """Return current voice settings as JSON."""
    return await asyncio.to_thread(_load_voice_settings)


@router.post("/settings/save")
async def voice_settings_save(
    rate: int = Form(175),
    volume: float = Form(0.9),
    voice_id: str = Form(""),
):
    """Persist voice settings and apply them to the running TTS engine."""
    rate = max(50, min(400, rate))
    volume = max(0.0, min(1.0, volume))
    data = {"rate": rate, "volume": volume, "voice_id": voice_id}

    # Apply to the live TTS engine (graceful degradation when unavailable)
    try:
        from timmy_serve.voice_tts import voice_tts

        if voice_tts.available:
            await asyncio.to_thread(voice_tts.set_rate, rate)
            await asyncio.to_thread(voice_tts.set_volume, volume)
            if voice_id:
                await asyncio.to_thread(voice_tts.set_voice, voice_id)
    except Exception as exc:
        logger.warning("Voice settings: failed to apply to TTS engine — %s", exc)

    await asyncio.to_thread(_save_voice_settings, data)
    return {"saved": True, "settings": data}
