"""
Tests for SpeechBridge Core Module
===================================

Тесты для базовых компонентов фреймворка:
- Импорт модулей
- GPU detection
- Базовые классы
- Исключения
"""

import pytest
import sys
from pathlib import Path

# Добавляем speechbridge в путь
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

from speechbridge import __version__
from speechbridge.core import (
    SpeechBridgeException,
    GPUException,
    ConfigException,
    ComponentException,
    GPUManager
)
from speechbridge.core.base import BaseComponent, BaseProcessor
from speechbridge.core.types import GPUInfo, DeviceType


class TestImports:
    """Тесты импортов"""

    def test_version_import(self):
        """Тест импорта версии"""
        assert __version__ is not None
        assert isinstance(__version__, str)
        assert len(__version__.split('.')) == 3  # Major.Minor.Patch

    def test_exceptions_import(self):
        """Тест импорта исключений"""
        assert SpeechBridgeException is not None
        assert GPUException is not None
        assert ConfigException is not None
        assert ComponentException is not None

    def test_gpu_manager_import(self):
        """Тест импорта GPU Manager"""
        assert GPUManager is not None


class TestExceptions:
    """Тесты исключений"""

    def test_base_exception(self):
        """Тест базового исключения"""
        exc = SpeechBridgeException("Test error")
        assert str(exc) == "Test error"
        assert exc.message == "Test error"
        assert exc.details == {}

    def test_exception_with_details(self):
        """Тест исключения с деталями"""
        details = {'code': 500, 'info': 'test'}
        exc = SpeechBridgeException("Test error", details)
        assert "Details:" in str(exc)
        assert exc.details == details

    def test_gpu_exception(self):
        """Тест GPU исключения"""
        exc = GPUException("GPU error")
        assert isinstance(exc, SpeechBridgeException)
        assert str(exc) == "GPU error"

    def test_config_exception(self):
        """Тест Config исключения"""
        exc = ConfigException("Config error")
        assert isinstance(exc, SpeechBridgeException)

    def test_component_exception(self):
        """Тест Component исключения"""
        exc = ComponentException("Component error")
        assert isinstance(exc, SpeechBridgeException)


class TestGPUManager:
    """Тесты GPU Manager"""

    def test_gpu_manager_singleton(self):
        """Тест singleton паттерна"""
        manager1 = GPUManager()
        manager2 = GPUManager()
        assert manager1 is manager2

    def test_gpu_detection(self):
        """Тест определения GPU"""
        manager = GPUManager()
        gpu_info = manager.get_gpu_info()

        assert isinstance(gpu_info, dict)
        assert 'cuda_available' in gpu_info
        assert 'mps_available' in gpu_info
        assert 'optimal_device' in gpu_info
        assert isinstance(gpu_info['cuda_available'], bool)
        assert isinstance(gpu_info['mps_available'], bool)

    def test_optimal_device(self):
        """Тест определения оптимального устройства"""
        manager = GPUManager()
        device = manager.get_optimal_device()

        assert device in ['cuda', 'mps', 'cpu']

    def test_device_name(self):
        """Тест получения имени устройства"""
        manager = GPUManager()
        device_name = manager.get_device_name()

        assert isinstance(device_name, str)
        assert len(device_name) > 0

    def test_gpu_available(self):
        """Тест проверки доступности GPU"""
        manager = GPUManager()
        is_available = manager.is_gpu_available()

        assert isinstance(is_available, bool)

    def test_memory_info(self):
        """Тест получения информации о памяти"""
        manager = GPUManager()
        memory_info = manager.get_memory_info()

        assert isinstance(memory_info, dict)

    def test_set_device_cpu(self):
        """Тест установки CPU устройства"""
        manager = GPUManager()
        manager.set_device('cpu')
        assert manager.get_optimal_device() == 'cpu'

    def test_set_invalid_device(self):
        """Тест установки недоступного устройства"""
        manager = GPUManager()

        # Если CUDA недоступна, должно вызываться исключение
        gpu_info = manager.get_gpu_info()
        if not gpu_info['cuda_available']:
            with pytest.raises(GPUException):
                manager.set_device('cuda')

    def test_clear_cache(self):
        """Тест очистки кэша GPU"""
        manager = GPUManager()
        # Не должно вызывать ошибок даже если GPU недоступен
        manager.clear_cache()


class TestBaseComponent:
    """Тесты базового компонента"""

    class DummyComponent(BaseComponent):
        """Тестовый компонент"""

        def initialize(self):
            self._initialized = True

        def validate_config(self):
            return True

    def test_component_creation(self):
        """Тест создания компонента"""
        component = self.DummyComponent()
        assert component is not None
        assert isinstance(component, BaseComponent)

    def test_component_config(self):
        """Тест конфигурации компонента"""
        config = {'test': 'value'}
        component = self.DummyComponent(config)
        assert component.config == config

    def test_component_device(self):
        """Тест устройства компонента"""
        component = self.DummyComponent()
        assert component.device in ['cuda', 'mps', 'cpu']

    def test_component_logger(self):
        """Тест логгера компонента"""
        component = self.DummyComponent()
        assert component.logger is not None
        assert 'dummycomponent' in component.logger.name.lower()

    def test_component_initialization(self):
        """Тест инициализации компонента"""
        component = self.DummyComponent()
        assert not component.is_initialized()

        component.initialize()
        assert component.is_initialized()

    def test_component_info(self):
        """Тест получения информации о компоненте"""
        component = self.DummyComponent()
        info = component.get_info()

        assert isinstance(info, dict)
        assert 'name' in info
        assert 'device' in info
        assert 'initialized' in info
        assert 'config' in info


class TestBaseProcessor:
    """Тесты базового процессора"""

    class DummyProcessor(BaseProcessor):
        """Тестовый процессор"""

        def initialize(self):
            self._initialized = True

        def validate_config(self):
            return True

        def process(self, input_data):
            return f"processed: {input_data}"

    def test_processor_creation(self):
        """Тест создания процессора"""
        processor = self.DummyProcessor()
        assert processor is not None
        assert isinstance(processor, BaseProcessor)

    def test_processor_process(self):
        """Тест обработки данных"""
        processor = self.DummyProcessor()
        result = processor.process("test")
        assert result == "processed: test"

    def test_processor_preprocess(self):
        """Тест предобработки"""
        processor = self.DummyProcessor()
        result = processor.preprocess("test")
        assert result == "test"

    def test_processor_postprocess(self):
        """Тест постобработки"""
        processor = self.DummyProcessor()
        result = processor.postprocess("test")
        assert result == "test"


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