"""
Speech Recognition Module for FMUS-VID.

This module provides speech recognition capabilities for transcribing audio
in both batch and streaming modes using various backend implementations.
"""

import abc
from typing import Optional, Union, Dict, List, Generator, AsyncGenerator, Any
import numpy as np

# Import WhisperTranscriber and FasterWhisperTranscriber
from .whisper import WhisperTranscriber, FasterWhisperTranscriber

# Conditionally import Home Assistant integration
try:
    from .integrations.home_assistant import HomeAssistantWhisperIntegration, HOME_ASSISTANT_AVAILABLE
except ImportError:
    HOME_ASSISTANT_AVAILABLE = False

# Define module exports
__all__ = [
    "BaseSpeechRecognizer",
    "WhisperTranscriber",
    "FasterWhisperTranscriber",
    "get_transcriber",
]

# Add Home Assistant integration if available
if HOME_ASSISTANT_AVAILABLE:
    __all__.append("HomeAssistantWhisperIntegration")


class BaseSpeechRecognizer(abc.ABC):
    """
    Abstract base class for speech recognition implementations.

    All speech recognizers must implement these core methods for transcribing audio
    in both batch and streaming modes.
    """

    @abc.abstractmethod
    def transcribe(
        self,
        audio: Union[str, np.ndarray, bytes],
        language: Optional[str] = None,
        translate: Optional[bool] = None,
        **kwargs
    ) -> Dict[str, Any]:
        """
        Transcribe audio in batch mode.

        Args:
            audio: Audio file path, numpy array, or bytes
            language: Language code (None for auto-detection)
            translate: Whether to translate to English
            **kwargs: Additional arguments to pass to the transcriber

        Returns:
            Dict containing the transcription results
        """
        pass

    @abc.abstractmethod
    def start_streaming(self) -> bool:
        """
        Start streaming mode for real-time transcription.

        Returns:
            True if streaming started successfully, False otherwise
        """
        pass

    @abc.abstractmethod
    def stop_streaming(self) -> None:
        """Stop streaming mode."""
        pass

    @abc.abstractmethod
    def add_audio_chunk(self, audio: np.ndarray) -> None:
        """
        Add an audio chunk to the streaming buffer.

        Args:
            audio: Audio chunk as numpy array
        """
        pass

    @abc.abstractmethod
    def get_transcript(self, timeout: float = 0.0) -> Optional[Dict]:
        """
        Get the latest transcript from streaming mode.

        Args:
            timeout: Time to wait for a transcript (0 for non-blocking)

        Returns:
            Transcript dict, or None if no transcript is available
        """
        pass

    @abc.abstractmethod
    def transcribe_stream(
        self,
        audio_chunks: Generator[np.ndarray, None, None]
    ) -> Generator[str, None, None]:
        """
        Transcribe a stream of audio chunks.

        Args:
            audio_chunks: Generator yielding audio chunks

        Yields:
            Transcribed text as it becomes available
        """
        pass

    @abc.abstractmethod
    async def transcribe_chunk(self, audio: np.ndarray) -> Optional[str]:
        """
        Transcribe a single audio chunk asynchronously.

        Args:
            audio: Audio chunk as numpy array

        Returns:
            Transcribed text, or None if no speech was detected
        """
        pass

    @abc.abstractmethod
    async def aiter_transcribe(
        self,
        audio_chunks: AsyncGenerator[np.ndarray, None]
    ) -> AsyncGenerator[str, None]:
        """
        Asynchronously transcribe a stream of audio chunks.

        Args:
            audio_chunks: Async generator yielding audio chunks

        Yields:
            Transcribed text as it becomes available
        """
        pass


def get_transcriber(
    transcriber_type: str = "whisper",
    model: str = "base",
    device: str = "cpu",
    **kwargs
) -> BaseSpeechRecognizer:
    """
    Factory function to get the best available speech recognizer.

    Args:
        transcriber_type: Type of transcriber to use ("whisper", "faster_whisper", "home_assistant")
        model: Model name or size
        device: Device to use ("cpu", "cuda", "auto")
        **kwargs: Additional arguments to pass to the transcriber

    Returns:
        An instance of BaseSpeechRecognizer

    Raises:
        ImportError: If the requested transcriber is not available
        ValueError: If the transcriber type is not recognized
    """
    transcriber_type = transcriber_type.lower()

    if transcriber_type == "whisper":
        return WhisperTranscriber(model=model, device=device, **kwargs)

    elif transcriber_type == "faster_whisper":
        return FasterWhisperTranscriber(model=model, device=device, **kwargs)

    elif transcriber_type == "home_assistant":
        if not HOME_ASSISTANT_AVAILABLE:
            raise ImportError("Home Assistant Faster Whisper integration is not available. "
                            "Install the required dependencies first.")
        return HomeAssistantWhisperIntegration(model=model, **kwargs)

    else:
        raise ValueError(f"Unknown transcriber type: {transcriber_type}. "
                        "Available types are: 'whisper', 'faster_whisper', 'home_assistant'")
