"""
Tests for SpeechBridge Stage 5 Components
==========================================

Tests for Pipeline and Builder Pattern
"""

import pytest
import sys
from pathlib import Path
from unittest.mock import Mock, MagicMock

# Add speechbridge to path
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from speechbridge.core.pipeline import VideoTranslationPipeline
from speechbridge.core.builder import PipelineBuilder, create_pipeline
from speechbridge.components.speech.base import BaseSpeechRecognizer
from speechbridge.components.translation.base import BaseTranslator
from speechbridge.components.tts.base import BaseTTS
from speechbridge.components.video.base import BaseVideoProcessor


# Mock Components for Testing

class MockSpeechRecognizer(BaseSpeechRecognizer):
    """Mock speech recognizer for testing"""

    def initialize(self):
        self._initialized = True

    def transcribe(self, audio_path):
        return {
            'text': 'This is test transcription',
            'language': 'en',
            'confidence': 0.95,
            'duration': 10.0
        }

    def get_supported_languages(self):
        return ['en', 'ru', 'auto']


class MockTranslator(BaseTranslator):
    """Mock translator for testing"""

    def initialize(self):
        self._initialized = True

    def translate(self, text, source_lang=None, target_lang=None):
        return {
            'text': f'Translated: {text}',
            'source_lang': source_lang or 'en',
            'target_lang': target_lang or self.target_lang,
            'confidence': 0.90
        }

    def get_supported_languages(self):
        return {
            'source': ['en', 'ru', 'auto'],
            'target': ['en', 'ru', 'de']
        }


class MockTTS(BaseTTS):
    """Mock TTS for testing"""

    def initialize(self):
        self._initialized = True

    def synthesize(self, text, output_path, voice=None, language=None):
        # Create empty file
        Path(output_path).write_text('')
        return {
            'audio_path': output_path,
            'duration': 8.0,
            'voice': voice or self.voice,
            'language': language or self.language,
            'text_length': len(text)
        }

    def get_available_voices(self, language=None):
        return [
            {'name': 'voice1', 'language': 'en'},
            {'name': 'voice2', 'language': 'ru'}
        ]


class MockVideoProcessor(BaseVideoProcessor):
    """Mock video processor for testing"""

    def initialize(self):
        self._initialized = True

    def extract_audio(self, video_path, audio_path, audio_format='wav'):
        # Create empty audio file
        Path(audio_path).write_text('')
        return {
            'audio_path': audio_path,
            'duration': 10.0,
            'format': audio_format,
            'sample_rate': 16000
        }

    def merge_audio(self, video_path, audio_path, output_path, remove_original_audio=True):
        # Create empty output file
        Path(output_path).write_text('')
        return {
            'output_path': output_path,
            'duration': 10.0,
            'video_codec': 'libx264',
            'audio_codec': 'aac'
        }

    def get_video_info(self, video_path):
        return {
            'path': video_path,
            'duration': 10.0,
            'width': 1920,
            'height': 1080,
            'fps': 30.0,
            'video_codec': 'h264',
            'audio_codec': 'aac',
            'bitrate': 5000000,
            'size': 10000000
        }

    def convert_video(self, input_path, output_path, video_codec=None, audio_codec=None):
        return {
            'output_path': output_path,
            'duration': 10.0
        }


class TestVideoTranslationPipeline:
    """Tests for VideoTranslationPipeline"""

    def setup_method(self):
        """Setup test environment"""
        self.speech = MockSpeechRecognizer()
        self.translator = MockTranslator({'target_lang': 'ru'})
        self.tts = MockTTS()
        self.video = MockVideoProcessor()

    def test_pipeline_creation(self):
        """Test pipeline creation"""
        pipeline = VideoTranslationPipeline(
            self.speech,
            self.translator,
            self.tts,
            self.video
        )

        assert pipeline is not None
        assert isinstance(pipeline, VideoTranslationPipeline)

    def test_pipeline_config(self):
        """Test pipeline configuration"""
        config = {
            'temp_dir': 'test_temp',
            'keep_temp': True
        }
        pipeline = VideoTranslationPipeline(
            self.speech,
            self.translator,
            self.tts,
            self.video,
            config
        )

        assert pipeline.temp_dir == Path('test_temp')
        assert pipeline.keep_temp is True

    def test_pipeline_validate_components(self):
        """Test component validation"""
        pipeline = VideoTranslationPipeline(
            self.speech,
            self.translator,
            self.tts,
            self.video
        )

        assert pipeline.validate_components() is True

    def test_pipeline_get_info(self):
        """Test getting pipeline info"""
        pipeline = VideoTranslationPipeline(
            self.speech,
            self.translator,
            self.tts,
            self.video
        )

        info = pipeline.get_pipeline_info()

        assert 'speech_recognizer' in info
        assert 'translator' in info
        assert 'tts_engine' in info
        assert 'video_processor' in info
        assert 'gpu_info' in info

    def test_pipeline_repr(self):
        """Test pipeline string representation"""
        pipeline = VideoTranslationPipeline(
            self.speech,
            self.translator,
            self.tts,
            self.video
        )

        repr_str = repr(pipeline)
        assert 'VideoTranslationPipeline' in repr_str
        assert 'MockSpeechRecognizer' in repr_str

    def test_pipeline_progress_callback(self):
        """Test progress callback"""
        callback_calls = []

        def callback(percent, message):
            callback_calls.append((percent, message))

        config = {'progress_callback': callback}
        pipeline = VideoTranslationPipeline(
            self.speech,
            self.translator,
            self.tts,
            self.video,
            config
        )

        pipeline._update_progress(50, "Test message")

        assert len(callback_calls) == 1
        assert callback_calls[0] == (50, "Test message")


class TestPipelineBuilder:
    """Tests for PipelineBuilder"""

    def test_builder_creation(self):
        """Test builder creation"""
        builder = PipelineBuilder()
        assert builder is not None
        assert isinstance(builder, PipelineBuilder)

    def test_builder_with_whisper(self):
        """Test adding Whisper recognizer"""
        builder = PipelineBuilder().with_whisper(model='base')
        assert builder._speech_recognizer is not None

    def test_builder_with_deepl(self):
        """Test adding DeepL translator"""
        builder = PipelineBuilder().with_deepl(target_lang='ru')
        assert builder._translator is not None

    def test_builder_with_edge_tts(self):
        """Test adding Edge TTS"""
        builder = PipelineBuilder().with_edge_tts()
        assert builder._tts_engine is not None

    def test_builder_with_ffmpeg(self):
        """Test adding FFmpeg processor"""
        builder = PipelineBuilder().with_ffmpeg()
        assert builder._video_processor is not None

    def test_builder_with_config(self):
        """Test setting pipeline config"""
        builder = PipelineBuilder().with_config(
            temp_dir='custom_temp',
            keep_temp=True
        )

        assert builder._pipeline_config['temp_dir'] == 'custom_temp'
        assert builder._pipeline_config['keep_temp'] is True

    def test_builder_with_temp_dir(self):
        """Test setting temp directory"""
        builder = PipelineBuilder().with_temp_dir('my_temp')
        assert builder._pipeline_config['temp_dir'] == 'my_temp'

    def test_builder_with_progress_callback(self):
        """Test setting progress callback"""
        def callback(percent, message):
            pass

        builder = PipelineBuilder().with_progress_callback(callback)
        assert builder._pipeline_config['progress_callback'] == callback

    def test_builder_keep_temporary_files(self):
        """Test keeping temporary files"""
        builder = PipelineBuilder().keep_temporary_files(True)
        assert builder._pipeline_config['keep_temp'] is True

    def test_builder_build_missing_components(self):
        """Test building with missing components"""
        builder = PipelineBuilder()

        with pytest.raises(ValueError, match="Speech recognizer not configured"):
            builder.build()

    def test_builder_build_success(self):
        """Test successful build"""
        builder = (PipelineBuilder()
                   .with_whisper()
                   .with_edge_tts()
                   .with_ffmpeg())

        # Need translator
        with pytest.raises(ValueError, match="Translator not configured"):
            builder.build()

        # Add translator
        builder.with_deepl(target_lang='en')

        # Now should build successfully
        pipeline = builder.build()
        assert isinstance(pipeline, VideoTranslationPipeline)

    def test_builder_chaining(self):
        """Test fluent API chaining"""
        pipeline = (PipelineBuilder()
                    .with_whisper(model='tiny')
                    .with_deepl(target_lang='ru')
                    .with_edge_tts(rate=1.2)
                    .with_ffmpeg()
                    .with_temp_dir('test')
                    .keep_temporary_files(False)
                    .build())

        assert isinstance(pipeline, VideoTranslationPipeline)
        assert pipeline.temp_dir == Path('test')
        assert pipeline.keep_temp is False

    def test_builder_create_default(self):
        """Test default preset"""
        builder = PipelineBuilder.create_default()

        assert builder._speech_recognizer is not None
        assert builder._tts_engine is not None
        assert builder._video_processor is not None

    def test_builder_create_fast(self):
        """Test fast preset"""
        builder = PipelineBuilder.create_fast()

        assert builder._speech_recognizer is not None
        # Check it's using tiny model
        from speechbridge.components.speech.whisper import WhisperRecognizer
        if isinstance(builder._speech_recognizer, WhisperRecognizer):
            assert builder._speech_recognizer.model_name == 'tiny'

    def test_builder_create_quality(self):
        """Test quality preset"""
        builder = PipelineBuilder.create_quality()

        assert builder._speech_recognizer is not None
        # Check it's using large model
        from speechbridge.components.speech.whisper import WhisperRecognizer
        if isinstance(builder._speech_recognizer, WhisperRecognizer):
            assert builder._speech_recognizer.model_name == 'large-v3'

    def test_builder_with_custom_components(self):
        """Test using custom components"""
        speech = MockSpeechRecognizer()
        translator = MockTranslator({'target_lang': 'en'})
        tts = MockTTS()
        video = MockVideoProcessor()

        pipeline = (PipelineBuilder()
                    .with_speech_recognizer(speech)
                    .with_translator(translator)
                    .with_tts(tts)
                    .with_video_processor(video)
                    .build())

        assert pipeline.speech_recognizer is speech
        assert pipeline.translator is translator
        assert pipeline.tts_engine is tts
        assert pipeline.video_processor is video

    def test_builder_repr(self):
        """Test builder string representation"""
        builder = (PipelineBuilder()
                   .with_whisper()
                   .with_edge_tts())

        repr_str = repr(builder)
        assert 'PipelineBuilder' in repr_str
        assert 'WhisperRecognizer' in repr_str
        assert 'EdgeTTS' in repr_str


class TestCreatePipeline:
    """Tests for create_pipeline convenience function"""

    def test_create_pipeline_default(self):
        """Test creating pipeline with defaults"""
        pipeline = create_pipeline()

        assert isinstance(pipeline, VideoTranslationPipeline)
        assert pipeline.speech_recognizer is not None
        assert pipeline.tts_engine is not None
        assert pipeline.video_processor is not None

    def test_create_pipeline_with_params(self):
        """Test creating pipeline with parameters"""
        pipeline = create_pipeline(
            speech_model='tiny',
            target_language='ru',
            temp_dir='custom'
        )

        assert isinstance(pipeline, VideoTranslationPipeline)
        assert pipeline.temp_dir == Path('custom')


if __name__ == "__main__":
    pytest.main([__file__, "-v", "--tb=short"])
