"""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._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

        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)
                m = WhisperModel(model, device=dev, compute_type=ct)
                print(f"[blitztext] Whisper '{model}' loaded on {dev} ({ct})", file=sys.stderr)
                return m
            except Exception as exc:  # noqa: BLE001 - CUDA libs may be absent
                last_err = exc
                if dev != attempts[-1]:
                    print(f"[blitztext] {dev} unavailable ({exc}); trying next device", file=sys.stderr)
        raise RuntimeError(f"Failed to load Whisper model '{model}': {last_err}")

    def transcribe(self, audio_path: Path, language: str = "") -> str:
        segments, _info = self._model.transcribe(
            str(audio_path),
            language=language or None,
            beam_size=self.beam_size,
            vad_filter=True,
        )
        return " ".join(seg.text.strip() for seg in segments).strip()
