"""Tests for src/voice/pipeline.py::_filter_segments — STT hallucination gate.

The gate replaces faster-whisper's temperature-fallback re-decode (the source of
16-24s latency outliers) with zero-cost segment rejection on no_speech_prob,
avg_logprob, and compression_ratio.
"""
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Optional

sys.path.insert(0, str(Path(__file__).resolve().parent.parent))

from src.voice.pipeline import (  # noqa: E402
    AVG_LOGPROB_DROP_THRESHOLD,
    COMPRESSION_RATIO_DROP_THRESHOLD,
    NO_SPEECH_DROP_THRESHOLD,
    _filter_segments,
)


@dataclass
class FakeSeg:
    text: str = ""
    no_speech_prob: float = 0.0
    avg_logprob: Optional[float] = 0.0
    compression_ratio: Optional[float] = 1.0


def test_keeps_clean_segment():
    parts, worst = _filter_segments([FakeSeg(text="salut eco", avg_logprob=-0.3, compression_ratio=1.5)])
    assert parts == ["salut eco"]
    assert worst == 0.0


def test_drops_high_no_speech():
    seg = FakeSeg(text="hmm", no_speech_prob=NO_SPEECH_DROP_THRESHOLD + 0.1)
    parts, worst = _filter_segments([seg])
    assert parts == []
    assert worst == NO_SPEECH_DROP_THRESHOLD + 0.1  # still tracked for logging


def test_drops_low_avg_logprob_hallucination():
    # "Care pune o zana judiciul tugea" style: decoder unsure
    seg = FakeSeg(text="zana judiciul tugea", avg_logprob=AVG_LOGPROB_DROP_THRESHOLD - 0.5)
    parts, _ = _filter_segments([seg])
    assert parts == []


def test_drops_high_compression_ratio_loop():
    seg = FakeSeg(text="da da da da da", compression_ratio=COMPRESSION_RATIO_DROP_THRESHOLD + 1.0)
    parts, _ = _filter_segments([seg])
    assert parts == []


def test_keeps_when_metrics_missing():
    # Older/edge segments may not expose avg_logprob/compression_ratio
    seg = FakeSeg(text="ok", avg_logprob=None, compression_ratio=None)
    parts, _ = _filter_segments([seg])
    assert parts == ["ok"]


def test_drops_empty_text():
    parts, _ = _filter_segments([FakeSeg(text="   ", avg_logprob=-0.2)])
    assert parts == []


def test_worst_no_speech_is_max_across_segments():
    segs = [
        FakeSeg(text="a", no_speech_prob=0.1, avg_logprob=-0.2),
        FakeSeg(text="b", no_speech_prob=0.4, avg_logprob=-0.2),
    ]
    parts, worst = _filter_segments(segs)
    assert parts == ["a", "b"]
    assert worst == 0.4


def test_mixed_keep_and_drop():
    segs = [
        FakeSeg(text="bun venit", avg_logprob=-0.3),
        FakeSeg(text="garbage", avg_logprob=-3.0),       # dropped: low logprob
        FakeSeg(text="la revedere", avg_logprob=-0.5),
    ]
    parts, _ = _filter_segments(segs)
    assert parts == ["bun venit", "la revedere"]
