"""Acoustic echo test: play Kokoro speech through the real speakers and
measure what each mic path hears.

  RAW mic (sounddevice)      -> should hear it loud (echo problem)
  helper --bypass            -> should hear it loud (capture path alive)
  helper with AEC            -> should hear ~nothing (echo cancelled)

The bypass pass is the aliveness proof: same binary, same capture path,
only voice processing toggled.
"""

import subprocess
import threading
import time
import wave

import numpy as np
import sounddevice as sd

from voice.vad import VAD

with wave.open("/tmp/kokoro-sample.wav") as w:
    SAMPLE = (
        np.frombuffer(w.readframes(w.getnframes()), dtype=np.int16).astype(np.float32)
        / 32768.0
    )
PLAY_SR = 24_000
DUR = len(SAMPLE) / PLAY_SR


def vad_report(label: str, audio16k: np.ndarray) -> None:
    vad = VAD()
    probs = [
        vad.prob(audio16k[i : i + 512])
        for i in range(0, len(audio16k) - 512, 512)
    ]
    probs = np.array(probs) if probs else np.zeros(1)
    nz = int((audio16k != 0).sum())
    print(
        f"{label}:\n"
        f"    peak={np.abs(audio16k).max():.4f} nonzero_samples={nz} "
        f"vad_max={probs.max():.2f} frames>0.5={int((probs>0.5).sum())} "
        f">0.75={int((probs>0.75).sum())} >0.9={int((probs>0.9).sum())}"
    )


def helper_capture_during_playback(bypass: bool) -> np.ndarray:
    args = ["./helper/aecmic"] + (["--bypass"] if bypass else [])
    proc = subprocess.Popen(
        args, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=0
    )
    chunks: list[bytes] = []
    stop = threading.Event()

    def reader():
        while not stop.is_set():
            data = proc.stdout.read(4096)
            if not data:
                break
            chunks.append(data)

    t = threading.Thread(target=reader, daemon=True)
    t.start()
    time.sleep(1.0)  # spin-up
    chunks.clear()
    sd.play(SAMPLE, PLAY_SR)
    sd.wait()
    time.sleep(0.2)
    stop.set()
    proc.terminate()
    t.join(timeout=2)
    pcm16 = np.frombuffer(b"".join(chunks), dtype=np.int16)
    return pcm16.astype(np.float32) / 32768.0


def main() -> None:
    print(f"sample: {DUR:.1f}s of Kokoro speech at current volume\n")

    rec = sd.rec(int((DUR + 1) * 16000), samplerate=16000, channels=1,
                 dtype="float32")[:, 0]
    time.sleep(0.3)
    sd.play(SAMPLE, PLAY_SR)
    sd.wait()
    time.sleep(0.2)
    sd.stop()
    vad_report("RAW mic during playback   ", rec)

    audio = helper_capture_during_playback(bypass=True)
    print(f"  (bypass captured {len(audio)/16000:.1f}s)")
    vad_report("helper --bypass (no AEC)  ", audio)

    audio = helper_capture_during_playback(bypass=False)
    print(f"  (aec captured {len(audio)/16000:.1f}s)")
    vad_report("helper with AEC           ", audio)


if __name__ == "__main__":
    main()
