from .audio_utils import AudioUtils
from .logger import logger
import sounddevice as sd
import numpy as np
import threading
import queue
import time


class StreamRecorder:
    def __init__(self, transcriber, sample_rate=16000, chunk_duration=5, min_interval=2.0):
        self.transcriber = transcriber
        self.sample_rate = sample_rate
        self.chunk_duration = chunk_duration
        self.min_interval = min_interval
        
        self.is_recording = False
        self.audio_queue = queue.Queue()
        self.device_id = None
        self.audio_buffer = np.array([], dtype=np.float32)
        self.last_transcription_time = 0
        
        logger.info("StreamRecorder initialized")
    
    def set_device(self, device_id):
        """set listening device"""
        devices = AudioUtils.list_input_devices()
        self.device_id = devices[0]['index']
        logger.info(f"Audio device set to: {device_id}")
    
    def start_recording(self):
        """start recording"""
        self.is_recording = True
        self.audio_buffer = np.array([], dtype=np.float32)
        self.last_transcription_time = 0
        
        self.recording_thread = threading.Thread(target=self._record_audio, daemon=True)
        self.recording_thread.start()
        
        logger.info("Recording started")
    
    def stop_recording(self):
        """stop recording"""
        self.is_recording = False
        logger.info("Recording stopped")
    
    def _record_audio(self):
        """recording flow"""
        def callback(indata, frames, time, status):
            if self.is_recording:
                audio_data = indata[:, 0] if indata.ndim > 1 else indata
                self.audio_queue.put(audio_data.astype(np.float32))
        
        try:
            with sd.InputStream(
                device=self.device_id,
                channels=1,
                samplerate=self.sample_rate,
                callback=callback,
                blocksize=int(self.sample_rate * 0.1)
            ):
                while self.is_recording:
                    sd.sleep(100)
        except Exception as e:
            logger.error(f"Recording error: {e}")
    
    def get_audio_chunk(self):
        """get cuhnks to translate (in case it contains speech)"""
        frames_per_chunk = int(self.sample_rate * self.chunk_duration)
        
        # collecting data from queue
        while not self.audio_queue.empty() and len(self.audio_buffer) < frames_per_chunk * 2:
            try:
                chunk = self.audio_queue.get_nowait()
                self.audio_buffer = np.concatenate([self.audio_buffer, chunk])
            except queue.Empty:
                break
        
        # check interval between requests
        current_time = time.time()
        if current_time - self.last_transcription_time < self.min_interval:
            return None
        
        # case if we collected enough
        if len(self.audio_buffer) >= frames_per_chunk:
            audio_chunk = self.audio_buffer[:frames_per_chunk]
            
            # check speech in chunk
            if AudioUtils.has_speech(audio_chunk):
                self.audio_buffer = self.audio_buffer[frames_per_chunk:]
                self.last_transcription_time = current_time
                return audio_chunk
            else:
                # skip silent chunk
                self.audio_buffer = self.audio_buffer[frames_per_chunk:]
                return None
        
        return None
    
    def process_chunk(self):
        """translate next chunk"""
        audio_chunk = self.get_audio_chunk()
        if audio_chunk is not None and len(audio_chunk) > 0:
            text = self.transcriber.transcribe_audio_data(audio_chunk, self.sample_rate)
            return text
        return None