"""Text-to-Speech engine — reads proxym responses aloud.

Supports multiple backends:
  - ``espeak``: espeak-ng (lightweight, robotic voice)
  - ``piper``:  Piper TTS (neural, natural-sounding, ~100 MB model)

Requires system packages::

    # espeak
    sudo apt install espeak-ng

    # piper
    pip install piper-tts
"""

from __future__ import annotations

import shutil
import subprocess

import structlog

logger = structlog.get_logger()


class TTSEngine:
    """Text-to-speech engine with pluggable backends.

    Parameters
    ----------
    engine : str
        Backend to use: ``"espeak"`` or ``"piper"``.
    language : str
        Language code for TTS.
    """

    def __init__(self, engine: str = "espeak", language: str = "pl") -> None:
        self.engine = engine
        self.language = language
        self._validate()

    def _validate(self) -> None:
        """Check that the chosen backend is available."""
        if self.engine == "espeak":
            if not shutil.which("espeak-ng"):
                logger.warning("tts_espeak_not_found", hint="sudo apt install espeak-ng")
        elif self.engine == "piper":
            if not shutil.which("piper"):
                logger.warning("tts_piper_not_found", hint="pip install piper-tts")

    def speak(self, text: str) -> None:
        """Speak *text* using the configured engine.

        Silently does nothing if the engine binary is not available.
        """
        if not text:
            return

        try:
            if self.engine == "espeak":
                self._speak_espeak(text)
            elif self.engine == "piper":
                self._speak_piper(text)
            else:
                logger.warning("tts_unknown_engine", engine=self.engine)
        except FileNotFoundError:
            logger.warning("tts_binary_not_found", engine=self.engine)
        except Exception as exc:
            logger.warning("tts_error", engine=self.engine, error=str(exc))

    def _speak_espeak(self, text: str) -> None:
        subprocess.run(
            ["espeak-ng", "-v", self.language, text],
            check=False,
            capture_output=True,
        )

    def _speak_piper(self, text: str) -> None:
        model = f"{self.language}_PL-darkman-medium" if self.language == "pl" else "en_US-lessac-medium"
        subprocess.run(
            ["piper", "--model", model, "--output-raw"],
            input=text.encode(),
            check=False,
            capture_output=True,
        )
