"""Microphone recording by shelling out to a system recorder.

Records 16 kHz mono WAV (what Whisper wants) using whichever recorder is
available — no Python audio bindings or device configuration required.
"""

from __future__ import annotations

import shutil
import signal
import subprocess
import tempfile
from pathlib import Path

# Ordered by preference. Each maps a recorder name to an argv builder.
_RECORDERS: dict[str, list[str]] = {
    "pw-record": ["pw-record", "--rate", "16000", "--channels", "1", "--format", "s16"],
    "parecord": ["parecord", "--rate=16000", "--channels=1", "--format=s16le", "--file-format=wav"],
    "arecord": ["arecord", "-q", "-f", "S16_LE", "-r", "16000", "-c", "1", "-t", "wav"],
}


def detect_recorder(preference: str = "auto") -> str:
    if preference != "auto":
        if shutil.which(preference):
            return preference
        raise RuntimeError(f"Configured recorder '{preference}' not found on PATH.")
    for name in _RECORDERS:
        if shutil.which(name):
            return name
    raise RuntimeError("No recorder found (need one of: pw-record, parecord, arecord).")


class Recording:
    """A single in-progress recording. Start on construction, call stop()."""

    def __init__(self, recorder: str):
        self._tmp = Path(tempfile.mkstemp(prefix="blitztext-", suffix=".wav")[1])
        argv = list(_RECORDERS[recorder]) + [str(self._tmp)]
        # arecord writes to the file given as a positional arg; the others too.
        self._proc = subprocess.Popen(
            argv,
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL,
        )

    def stop(self) -> Path:
        """Stop recording, finalize the WAV, and return its path."""
        if self._proc.poll() is None:
            # SIGINT lets pw-record/arecord flush the WAV header cleanly.
            self._proc.send_signal(signal.SIGINT)
            try:
                self._proc.wait(timeout=5)
            except subprocess.TimeoutExpired:
                self._proc.terminate()
                self._proc.wait(timeout=5)
        return self._tmp

    def discard(self) -> None:
        if self._proc.poll() is None:
            self._proc.terminate()
            self._proc.wait(timeout=5)
        self._tmp.unlink(missing_ok=True)
