"""Test suite for Faster-Whisper STT Adapter.

This test suite validates:
1. Adapter initialization
2. Language support
3. Audio transcription (real audio files)
4. Network methods (bytes/array transcription)
5. Performance characteristics of faster-whisper

NOTE: These are REAL functional tests, not mocked tests.
"""

import pytest
import numpy as np
import tempfile
import os
from pathlib import Path
import wave

pytestmark = pytest.mark.model_download


def create_test_audio_file(duration_seconds=2, sample_rate=16000, frequency=440):
    """Create a test WAV file with a sine wave tone.
    
    Args:
        duration_seconds: Length of audio
        sample_rate: Sample rate in Hz
        frequency: Frequency of sine wave in Hz
        
    Returns:
        Path to created WAV file
    """
    # Generate sine wave
    t = np.linspace(0, duration_seconds, int(sample_rate * duration_seconds))
    audio = np.sin(2 * np.pi * frequency * t)
    
    # Convert to 16-bit PCM
    audio_int16 = (audio * 32767).astype(np.int16)
    
    # Create temporary WAV file
    tmp_file = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
    tmp_path = tmp_file.name
    tmp_file.close()
    
    # Write WAV file
    with wave.open(tmp_path, 'wb') as wav_file:
        wav_file.setnchannels(1)  # Mono
        wav_file.setsampwidth(2)   # 16-bit
        wav_file.setframerate(sample_rate)
        wav_file.writeframes(audio_int16.tobytes())
    
    return tmp_path


def test_faster_whisper_adapter_import():
    """Test that Faster-Whisper adapter can be imported."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
        assert FasterWhisperAdapter is not None
    except ImportError as e:
        pytest.skip(f"Faster-Whisper not installed: {e}")


def test_faster_whisper_adapter_initialization():
    """Test Faster-Whisper adapter initializes correctly."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')  # Use tiny for speed
    
    # Check availability
    is_available = adapter.is_available()
    assert isinstance(is_available, bool)
    
    if is_available:
        print(f"✅ Faster-Whisper initialized successfully")


def test_faster_whisper_supported_languages():
    """Test that Faster-Whisper supports required languages."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    supported_langs = adapter.get_supported_languages()
    
    # Must support at least: EN, FR, DE, ES, RU, ZH
    required_langs = ['en', 'fr', 'de', 'es', 'ru', 'zh']
    
    for lang in required_langs:
        assert lang in supported_langs, f"Language {lang} not supported by Faster-Whisper"
    
    print(f"✅ All {len(required_langs)} required languages supported")


def test_faster_whisper_transcribe():
    """Test basic transcription functionality with real audio."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    
    if not adapter.is_available():
        pytest.skip("Faster-Whisper not functional (model not available)")
    
    # Create test audio file
    audio_path = create_test_audio_file(duration_seconds=2)
    
    try:
        # Transcribe (will likely return empty or gibberish for sine wave, but tests the pipeline)
        text = adapter.transcribe(audio_path, language='en')
        
        # Verify output
        assert isinstance(text, str), "Transcription should return string"
        print(f"✅ Transcription completed: '{text}' (length: {len(text)} chars)")
        
    finally:
        # Clean up
        if os.path.exists(audio_path):
            os.unlink(audio_path)


def test_faster_whisper_transcribe_from_bytes():
    """Test transcription from bytes (network use case)."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    
    if not adapter.is_available():
        pytest.skip("Faster-Whisper not functional")
    
    # Create test audio file
    audio_path = create_test_audio_file(duration_seconds=2)
    
    try:
        # Read file as bytes
        with open(audio_path, 'rb') as f:
            audio_bytes = f.read()
        
        # Transcribe from bytes
        text = adapter.transcribe_from_bytes(audio_bytes, language='en')
        
        # Verify output
        assert isinstance(text, str), "Transcription should return string"
        print(f"✅ Transcription from bytes completed: length {len(text)} chars")
        
    finally:
        # Clean up
        if os.path.exists(audio_path):
            os.unlink(audio_path)


def test_faster_whisper_transcribe_from_array():
    """Test transcription from numpy array."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    
    if not adapter.is_available():
        pytest.skip("Faster-Whisper not functional")
    
    # Generate sine wave audio
    sample_rate = 16000
    duration = 2
    t = np.linspace(0, duration, int(sample_rate * duration))
    audio_array = np.sin(2 * np.pi * 440 * t).astype(np.float32)
    
    # Transcribe from array
    text = adapter.transcribe_from_array(audio_array, sample_rate, language='en')
    
    # Verify output
    assert isinstance(text, str), "Transcription should return string"
    print(f"✅ Transcription from array completed: length {len(text)} chars")


def test_faster_whisper_language_switching():
    """Test switching between languages."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    
    if not adapter.is_available():
        pytest.skip("Faster-Whisper not functional")
    
    # Test switching to French
    success = adapter.set_language('fr')
    assert isinstance(success, bool), "set_language should return bool"
    assert success, "Setting French language should succeed"
    
    # Test switching to German
    success = adapter.set_language('de')
    assert success, "Setting German language should succeed"
    
    print("✅ Language switching working correctly")


def test_faster_whisper_model_switching():
    """Test switching between different model sizes."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    
    if not adapter.is_available():
        pytest.skip("Faster-Whisper not functional")
    
    # Try switching to base model (will download if not cached)
    # Skip if download would take too long
    print("⚠️  Skipping model switch test to avoid long download")
    pytest.skip("Model switching test skipped to avoid downloads")


def test_faster_whisper_get_info():
    """Test getting adapter metadata."""
    try:
        from abstractvoice.adapters.stt_faster_whisper import FasterWhisperAdapter
    except ImportError:
        pytest.skip("Faster-Whisper not installed")
    
    adapter = FasterWhisperAdapter(model_size='tiny')
    info = adapter.get_info()
    
    # Verify metadata structure
    assert 'name' in info
    assert 'languages' in info
    assert 'available' in info
    assert 'engine' in info
    assert info['engine'] == 'Faster-Whisper'
    assert 'model_size' in info
    assert info['model_size'] == 'tiny'
    assert 'device' in info
    assert 'compute_type' in info
    
    print(f"✅ Adapter info: {info['engine']} ({info['model_size']}, {info['compute_type']})")


def test_voice_manager_integration():
    """Test that VoiceManager can use Faster-Whisper adapter."""
    try:
        from abstractvoice import VoiceManager
    except ImportError as e:
        pytest.skip(f"AbstractVoice not installed: {e}")
    
    # Initialize VoiceManager (it should handle STT internally)
    vm = VoiceManager(
        language='en',
        whisper_model='tiny',
        stt_engine='faster_whisper',
        remote_api_key='sk-test',
        debug_mode=False,
    )
    
    # VoiceManager doesn't expose STT adapter directly yet
    # This test verifies it initializes without error
    assert vm is not None
    print("✅ VoiceManager initialized successfully")


def test_voice_manager_transcribe_methods():
    """Test VoiceManager transcription methods."""
    try:
        from abstractvoice import VoiceManager
    except ImportError as e:
        pytest.skip(f"AbstractVoice not installed: {e}")
    
    vm = VoiceManager(
        language='en',
        whisper_model='tiny',
        stt_engine='faster_whisper',
        remote_api_key='sk-test',
        debug_mode=False,
    )
    
    # Create test audio file
    audio_path = create_test_audio_file(duration_seconds=2)
    
    try:
        # Test transcribe_file (already implemented in VoiceManager)
        text = vm.transcribe_file(audio_path, language='en')
        assert isinstance(text, str)
        print(f"✅ transcribe_file() working: '{text}'")
        
        # Test transcribe_from_bytes
        with open(audio_path, 'rb') as f:
            audio_bytes = f.read()
        
        text = vm.transcribe_from_bytes(audio_bytes, language='en')
        assert isinstance(text, str)
        print(f"✅ transcribe_from_bytes() working: '{text}'")
        
    finally:
        # Clean up
        if os.path.exists(audio_path):
            os.unlink(audio_path)


if __name__ == '__main__':
    # Run tests with verbose output
    pytest.main([__file__, '-v', '-s'])
