import sys
import queue
import threading
import time

import numpy as np
import sounddevice as sd

from .compressor import Compressor
from .model import SAMPLE_RATE, transcribe_audio
from .vad import DEFAULT_SILENCE_FRAMES, FRAME_SIZE, VADStateMachine, calibrate_silence, describe_input_device, resample_to_target, resolve_input_rate


def stream_transcribe(processor, model, language, silence_frames=DEFAULT_SILENCE_FRAMES, device=None, normalize=False):
    print(f"Using input device: {describe_input_device(device)}")
    comp = Compressor() if normalize else None
    if comp:
        print("  Normalization: compressor+limiter enabled")
    threshold = calibrate_silence(device=device, compressor=comp)
    capture_rate = resolve_input_rate(device)
    capture_blocksize = FRAME_SIZE * capture_rate // SAMPLE_RATE
    vad = VADStateMachine(threshold, silence_frames=silence_frames)
    seg_queue = queue.Queue()
    stop_event = threading.Event()
    start_time = time.monotonic()

    def transcription_worker():
        while not stop_event.is_set() or not seg_queue.empty():
            try:
                seg_start, audio = seg_queue.get(timeout=0.5)
            except queue.Empty:
                continue
            minutes = int(seg_start) // 60
            seconds = int(seg_start) % 60
            text = transcribe_audio(processor, model, audio, language)
            if text.strip():
                print(f"[{minutes:02d}:{seconds:02d}] {text.strip()}")

    worker = threading.Thread(target=transcription_worker, daemon=True)
    worker.start()

    def audio_callback(indata, frames, time_info, status):
        if stop_event.is_set():
            return
        elapsed = time.monotonic() - start_time
        frame = resample_to_target(indata[:, 0].copy(), capture_rate)
        if comp is not None:
            frame = comp.process(frame)
        result = vad.process_frame(frame, elapsed)
        if result is not None:
            seg_queue.put(result)

    print("Listening... (Ctrl+C to stop)")
    stream = sd.InputStream(
        samplerate=capture_rate, channels=1, dtype="float32",
        callback=audio_callback, blocksize=capture_blocksize, device=device,
    )

    try:
        with stream:
            while True:
                time.sleep(0.1)
    except KeyboardInterrupt:
        pass

    stop_event.set()

    if vad.speaking and vad.segment:
        seg_queue.put((vad.segment_start_time, np.concatenate(vad.segment)))

    worker.join(timeout=30)
    if worker.is_alive():
        print("Warning: transcription worker did not finish in time.", file=sys.stderr)
    print("\nDone.")
