"""Audio transcription sensor (optional, local-only)."""

from __future__ import annotations

from pathlib import Path

from neurovault.sensors.base import BaseSensor


class AudioSensor(BaseSensor):
    """Transcribe local audio files using whisper when available."""

    name = "audio"
    source_tag = "audio"
    poll_interval = 300.0

    _extensions = {".m4a", ".mp3", ".wav", ".ogg", ".webm"}

    def __init__(self, watch_paths: list[str] | None = None):
        self._watch_paths = watch_paths or [
            str(Path.home() / "Recordings"),
            str(Path.home() / "Voice Memos"),
        ]
        self._seen_files: set[str] = set()
        self._whisper_model = None
        self._whisper_unavailable = False

    def poll(self) -> list[tuple[str, dict]]:
        results: list[tuple[str, dict]] = []
        for base in self._watch_paths:
            root = Path(base).expanduser()
            if not root.exists():
                continue
            for file_path in root.rglob("*"):
                if not file_path.is_file() or file_path.suffix.lower() not in self._extensions:
                    continue
                key = str(file_path)
                if key in self._seen_files:
                    continue
                transcript = self._transcribe(file_path)
                self._seen_files.add(key)
                if not transcript:
                    continue
                results.append(
                    (
                        transcript,
                        {
                            "content_type": "audio_transcript",
                            "file_path": str(file_path),
                            "file_name": file_path.name,
                        },
                    )
                )
        return results

    def _transcribe(self, file_path: Path) -> str:
        model = self._load_model()
        if model is None:
            return ""

        try:
            out = model.transcribe(str(file_path), fp16=False)
            return (out.get("text") or "").strip()
        except Exception:
            return ""

    def _load_model(self):
        if self._whisper_unavailable:
            return None
        if self._whisper_model is not None:
            return self._whisper_model
        try:
            import whisper  # type: ignore
        except Exception:
            self._whisper_unavailable = True
            return None
        try:
            self._whisper_model = whisper.load_model("tiny")
        except Exception:
            self._whisper_unavailable = True
            return None
        return self._whisper_model
