"""Local speech-to-text via faster-whisper (CTranslate2).

The model is loaded once and reused. On this arm64 host the CTranslate2 wheel is
CPU-only, so device="auto" attempts CUDA and falls back to CPU automatically.
"""

from __future__ import annotations

import sys
from pathlib import Path


class Transcriber:
    def __init__(
        self,
        model: str = "small",
        device: str = "auto",
        compute_type: str = "auto",
        beam_size: int = 5,
    ):
        self.beam_size = beam_size
        self.device = "cpu"  # resolved actual device, set by _load
        self._model = self._load(model, device, compute_type)

    @staticmethod
    def _resolve_compute_type(device: str, requested: str) -> str:
        if requested != "auto":
            return requested
        return "float16" if device == "cuda" else "int8"

    def _load(self, model: str, device: str, compute_type: str):
        from faster_whisper import WhisperModel

        from .logbuffer import log

        attempts: list[str]
        if device == "auto":
            attempts = ["cuda", "cpu"]
        else:
            attempts = [device]

        last_err: Exception | None = None
        for dev in attempts:
            try:
                ct = self._resolve_compute_type(dev, compute_type)
                log(f"Loading Whisper '{model}' on {dev} ({ct})… (first run may download the model)")
                m = WhisperModel(model, device=dev, compute_type=ct)
                log(f"Whisper '{model}' ready on {dev} ({ct})")
                self.device = dev
                return m
            except Exception as exc:  # noqa: BLE001 - CUDA libs may be absent
                last_err = exc
                if dev != attempts[-1]:
                    log(f"{dev} unavailable ({exc}); trying next device")
        raise RuntimeError(f"Failed to load Whisper model '{model}': {last_err}")

    def transcribe(self, audio_path: Path, language: str = "", hotwords: str = "",
                   beam_size: int | None = None) -> str:
        kwargs = dict(language=language or None,
                      beam_size=beam_size if beam_size is not None else self.beam_size,
                      vad_filter=True)
        if hotwords:
            # Bias recognition toward the routing keywords so they transcribe
            # reliably. Older faster-whisper builds lack `hotwords`; fall back.
            kwargs["hotwords"] = hotwords
        try:
            segments, _info = self._model.transcribe(str(audio_path), **kwargs)
        except TypeError:
            kwargs.pop("hotwords", None)
            segments, _info = self._model.transcribe(str(audio_path), **kwargs)
        return " ".join(seg.text.strip() for seg in segments).strip()
