"""Speech-to-text service using faster-whisper (in-process, CPU/GPU)."""
import asyncio
import logging
import tempfile
import time
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from faster_whisper import WhisperModel

logger = logging.getLogger(__name__)

_model: "WhisperModel | None" = None
_model_lock = asyncio.Lock()
_load_error: str | None = None


async def load_stt_model() -> None:
    """Load the Whisper model. Called once at startup when voice is enabled."""
    global _model, _load_error
    from fabledassistant.services.voice_config import get_stt_model, is_voice_enabled

    if not await is_voice_enabled():
        return

    async with _model_lock:
        if _model is not None:
            return
        try:
            from faster_whisper import WhisperModel

            model_name = await get_stt_model()
            logger.info("Loading Whisper STT model '%s'...", model_name)
            loop = asyncio.get_running_loop()
            _model = await loop.run_in_executor(
                None,
                lambda: WhisperModel(model_name, device="cpu", compute_type="int8"),
            )
            logger.info("Whisper STT model '%s' loaded", model_name)
        except Exception:
            _load_error = "Failed to load Whisper STT model"
            logger.exception(_load_error)


async def reload_stt_model() -> None:
    """Unload the current model and reload with the current config. Safe to call at runtime."""
    global _model, _load_error
    async with _model_lock:
        _model = None
        _load_error = None
    await load_stt_model()


def stt_available() -> bool:
    return _model is not None


async def transcribe(audio_bytes: bytes, mime_type: str = "audio/webm", initial_prompt: str | None = None) -> str:
    """Transcribe audio bytes to text. Runs the model in a thread executor.

    initial_prompt: optional text to bias the model toward domain-specific vocabulary
    (e.g. recent conversation context). Reduces mishearings like "gold" for "cold".
    """
    if _model is None:
        raise RuntimeError("STT model not loaded")

    suffix = ".webm"
    if "ogg" in mime_type:
        suffix = ".ogg"
    elif "wav" in mime_type:
        suffix = ".wav"
    elif "mp4" in mime_type or "m4a" in mime_type:
        suffix = ".mp4"

    def _run() -> str:
        with tempfile.NamedTemporaryFile(suffix=suffix, delete=True) as f:
            f.write(audio_bytes)
            f.flush()
            t0 = time.monotonic()
            segments, _ = _model.transcribe(  # type: ignore[union-attr]
                f.name,
                beam_size=5,
                initial_prompt=initial_prompt or None,
            )
            text = " ".join(seg.text.strip() for seg in segments).strip()
            logger.debug("STT transcription took %.2fs", time.monotonic() - t0)
            return text

    loop = asyncio.get_running_loop()
    return await loop.run_in_executor(None, _run)
