"""Einfache energie-basierte Sprachaktivitaetserkennung (VAD).

Reines Python (stdlib `array`), arbeitet auf s16le-PCM (mono). Erkennt das Ende
einer Aeusserung anhand andauernder Stille nach erkannter Sprache. Damit kann der
Server in /ws/voice Aeusserungen automatisch segmentieren, ohne dass der Client
ein explizites Ende-Signal schickt.

Hinweis: Das ersetzt keinen echten Streaming-STT-Dienst (keine wortweisen
Teil-Transkripte) - es bestimmt nur die Aeusserungsgrenzen.
"""

import array
import math


def rms(pcm: bytes) -> float:
    """Lautstaerke (RMS) eines s16le-PCM-Puffers; 0.0 bei leerem Puffer."""
    usable = len(pcm) - (len(pcm) % 2)
    if usable <= 0:
        return 0.0
    samples = array.array("h")
    samples.frombytes(pcm[:usable])
    if not samples:
        return 0.0
    return math.sqrt(sum(s * s for s in samples) / len(samples))


class EnergyVAD:
    def __init__(self, sample_rate: int = 16000, threshold: float = 500.0, silence_ms: float = 700.0):
        self.sample_rate = sample_rate
        self.threshold = threshold
        self.silence_ms = silence_ms
        self._speech_started = False
        self._silence_ms = 0.0

    def feed(self, pcm: bytes) -> bool:
        """Verarbeitet einen Audio-Chunk.

        Liefert True, sobald nach erkannter Sprache genug Stille (silence_ms)
        vergangen ist - die Aeusserung gilt dann als beendet.
        """
        level = rms(pcm)
        n_samples = len(pcm) // 2
        chunk_ms = (n_samples / self.sample_rate) * 1000.0 if self.sample_rate else 0.0

        if level >= self.threshold:
            self._speech_started = True
            self._silence_ms = 0.0
            return False

        if self._speech_started:
            self._silence_ms += chunk_ms
            if self._silence_ms >= self.silence_ms:
                return True
        return False

    def reset(self) -> None:
        self._speech_started = False
        self._silence_ms = 0.0
