"""Proactive-announcement test: worker reports flow to the MASTER agent,
who speaks them — interjecting when idle, folding into the turn when a
question arrives at the same time.

  1. spoken delegation request -> master delegates, answers, keeps free
  2. real worker finishes -> writes control/report.txt -> master
     announces it PROACTIVELY during silence (no user speech!)
  3. injected report + new question together -> ONE combined master turn
"""

import asyncio
import os
import pathlib
import time

import numpy as np

os.environ["SPEAKER_PROFILE"] = "/tmp/spk-e2e-profile.npz"
pathlib.Path("/tmp/spk-e2e-profile.npz").unlink(missing_ok=True)
os.environ["RESUME"] = "0"

import main as appmod
from main import VoiceApp

import voice.control as control
control.SESSION_FILE = pathlib.Path("/tmp/spk-e2e-session")

SR, F = 16_000, 512
TASK_ASK = np.fromfile("/tmp/spk/task_ask.f32", dtype=np.float32)
QUESTION = np.fromfile("/tmp/claude-voice-test.f32", dtype=np.float32)


class FakeMic:
    def __init__(self):
        self.frames: asyncio.Queue[np.ndarray] = asyncio.Queue()
    def start(self): pass
    def stop(self): pass


async def feed(mic, audio):
    n = len(audio) // F
    for i in range(n):
        await mic.frames.put(audio[i * F:(i + 1) * F].copy())
        await asyncio.sleep(F / SR)


async def driver(app):
    mic = app.mic
    silence = np.zeros(F * 4, dtype=np.float32)
    await asyncio.sleep(1.0)

    print("[driver] 1) spoken delegation request")
    await feed(mic, TASK_ASK)
    # idle silence: worker should finish and the master should announce
    t0 = time.monotonic()
    announced = False
    while time.monotonic() - t0 < 90:
        await feed(mic, silence)
        if (control.CONTROL / "report.txt").is_file():
            announced = True  # watcher will pick it up within 0.5s
        if announced and app.inbox.empty() and not app.responding \
                and not app.speaker.speaking and time.monotonic() - t0 > 30:
            break
    print("[driver] 2) idle phase over; now combined turn "
          "(inject report + speak at once)")
    (control.CONTROL / "report.txt").write_text(
        "The email to Sarah about the Q3 numbers was sent successfully.\n")
    await asyncio.sleep(0.7)  # watcher tick
    await feed(mic, QUESTION)
    t0 = time.monotonic()
    while time.monotonic() - t0 < 30:
        await feed(mic, silence)
    print("[driver] done")


async def run_test():
    app = VoiceApp()
    app.mic = FakeMic()
    for _ in range(20):
        app.mic.frames.put_nowait(np.zeros(F, dtype=np.float32))
    run_task = asyncio.create_task(app.run())
    try:
        await asyncio.wait_for(driver(app), timeout=200)
    except asyncio.TimeoutError:
        print("[driver] timed out")
    finally:
        run_task.cancel()
        await asyncio.gather(run_task, return_exceptions=True)


if __name__ == "__main__":
    asyncio.run(run_test())
