"""
VAD (语音活动检测) - 基于 webrtcvad

轻量级 C 库，无 torch 依赖，~200KB。
要求输入：16-bit PCM，帧长 10/20/30ms。
"""

import logging
import time
from typing import Optional

import webrtcvad

logger = logging.getLogger(__name__)


class VoiceActivityDetector:
    """
    语音活动检测器

    基于 webrtcvad，检测用户是否在说话以及是否说完。
    使用滑动窗口平滑判断，避免噪音误触发。
    """

    def __init__(
        self,
        aggressiveness: int = 2,
        sample_rate: int = 16000,
        silence_duration_ms: int = 1500,
        min_speech_ms: int = 300,
        speech_confirm_frames: int = 3,
    ):
        """
        Args:
            aggressiveness: VAD 灵敏度 (0-3, 3 最激进过滤非语音)
            sample_rate: 采样率 (8000/16000/32000/48000)
            silence_duration_ms: 静音判定时长（毫秒）
            min_speech_ms: 最短语音时长（毫秒），低于此不算有效语音
            speech_confirm_frames: 连续多少帧检测到语音才确认为说话（防噪音误触发）
        """
        self._vad = webrtcvad.Vad(aggressiveness)
        self._sample_rate = sample_rate
        self._silence_duration_ms = silence_duration_ms
        self._min_speech_ms = min_speech_ms
        self._speech_confirm_frames = speech_confirm_frames

        # 状态
        self._speech_confirmed = False  # 确认用户在说话
        self._consecutive_speech = 0     # 连续语音帧计数
        self._last_speech_time: Optional[float] = None
        self._speech_start_time: Optional[float] = None

    def is_speech(self, audio_chunk: bytes) -> bool:
        """
        检测音频帧是否包含语音

        Args:
            audio_chunk: PCM16 音频数据 (30ms = 960 bytes @16kHz)

        Returns:
            是否包含语音
        """
        try:
            result = self._vad.is_speech(audio_chunk, self._sample_rate)
        except Exception:
            return False

        now = time.time()

        if result:
            self._consecutive_speech += 1
            self._last_speech_time = now

            # 需要连续 N 帧语音才确认（防止噪音误触发）
            if not self._speech_confirmed and self._consecutive_speech >= self._speech_confirm_frames:
                self._speech_confirmed = True
                self._speech_start_time = now
        else:
            self._consecutive_speech = 0

        return result

    def is_speech_finished(self) -> bool:
        """
        判断用户是否说完

        条件：
        1. 确认说过话（连续 N 帧语音）
        2. 说话时长超过最短阈值
        3. 连续静音超过判定时长

        Returns:
            是否说完
        """
        if not self._speech_confirmed or self._last_speech_time is None:
            return False

        # 检查最短语音时长
        if self._speech_start_time is not None:
            speech_ms = (self._last_speech_time - self._speech_start_time) * 1000
            if speech_ms < self._min_speech_ms:
                return False

        # 检查静音时长
        elapsed_ms = (time.time() - self._last_speech_time) * 1000
        return elapsed_ms >= self._silence_duration_ms

    @property
    def has_speech(self) -> bool:
        """是否确认检测到有效语音"""
        return self._speech_confirmed

    @property
    def speech_duration(self) -> float:
        """语音持续时间（秒）"""
        if self._speech_start_time is None or self._last_speech_time is None:
            return 0.0
        return self._last_speech_time - self._speech_start_time

    def reset(self) -> None:
        """重置状态（新一轮监听前调用）"""
        self._speech_confirmed = False
        self._consecutive_speech = 0
        self._last_speech_time = None
        self._speech_start_time = None
