"""Tests pour la configuration du service."""

import json
import pytest

from audioin.config import AudioConfig, VADConfig, MQTTConfig, ServiceConfig


class TestAudioConfig:
    """Tests de la configuration audio."""

    def test_default_values(self):
        """Test valeurs par défaut."""
        config = AudioConfig()

        assert config.sample_rate == 16000
        assert config.channels == 1
        assert config.frame_size == 320
        assert config.device_name == "respeaker-2mic"

    def test_custom_values(self):
        """Test valeurs personnalisées."""
        config = AudioConfig(
            sample_rate=48000, channels=2, frame_size=960, device_name="custom-device"
        )

        assert config.sample_rate == 48000
        assert config.channels == 2
        assert config.frame_size == 960
        assert config.device_name == "custom-device"


class TestVADConfig:
    """Tests de la configuration VAD."""

    def test_default_values(self):
        """Test valeurs par défaut."""
        config = VADConfig()

        assert config.threshold == 0.3
        assert config.attack_ms == 80
        assert config.release_ms == 200
        assert config.eos_ms == 800

    def test_to_dict(self):
        """Test conversion en dictionnaire."""
        config = VADConfig(threshold=0.25, attack_ms=60, release_ms=150, eos_ms=600)

        expected = {
            "threshold": 0.25,
            "attack_ms": 60,
            "release_ms": 150,
            "eos_ms": 600,
        }

        assert config.to_dict() == expected

    def test_from_dict_complete(self):
        """Test création depuis dictionnaire complet."""
        data = {"threshold": 0.4, "attack_ms": 100, "release_ms": 300, "eos_ms": 1000}

        config = VADConfig.from_dict(data)

        assert config.threshold == 0.4
        assert config.attack_ms == 100
        assert config.release_ms == 300
        assert config.eos_ms == 1000

    def test_from_dict_partial(self):
        """Test création depuis dictionnaire partiel."""
        data = {"threshold": 0.5, "attack_ms": 120}

        config = VADConfig.from_dict(data)

        assert config.threshold == 0.5
        assert config.attack_ms == 120
        assert config.release_ms == 200  # Valeur par défaut
        assert config.eos_ms == 800  # Valeur par défaut

    def test_from_dict_empty(self):
        """Test création depuis dictionnaire vide."""
        config = VADConfig.from_dict({})

        assert config.threshold == 0.3
        assert config.attack_ms == 80
        assert config.release_ms == 200
        assert config.eos_ms == 800

    def test_from_json(self):
        """Test création depuis JSON."""
        json_str = '{"threshold": 0.35, "attack_ms": 90}'
        config = VADConfig.from_json(json_str)

        assert config.threshold == 0.35
        assert config.attack_ms == 90

    def test_from_json_invalid(self):
        """Test création depuis JSON invalide."""
        with pytest.raises(json.JSONDecodeError):
            VADConfig.from_json('{"invalid": json}')

    def test_validation_ranges(self):
        """Test que les valeurs sont dans des plages raisonnables."""
        config = VADConfig(threshold=0.0, attack_ms=10, release_ms=10, eos_ms=100)

        # Valeurs très petites mais techniquement valides
        assert config.threshold >= 0.0
        assert config.attack_ms > 0
        assert config.release_ms > 0
        assert config.eos_ms > 0


class TestMQTTConfig:
    """Tests de la configuration MQTT."""

    def test_default_values(self):
        """Test valeurs par défaut."""
        config = MQTTConfig()

        assert config.host == "127.0.0.1"
        assert config.port == 1883
        assert config.topic_rms == "audio/rms"
        assert config.topic_vad == "audio/vad"
        assert config.topic_capabilities == "audio/capabilities"
        assert config.topic_config == "audio/vad/config"
        assert config.client_id == "skull-audioin"
        assert config.keepalive == 60

    def test_custom_values(self):
        """Test valeurs personnalisées."""
        config = MQTTConfig(
            host="192.168.1.100",
            port=1884,
            topic_rms="custom/rms",
            client_id="custom-client",
        )

        assert config.host == "192.168.1.100"
        assert config.port == 1884
        assert config.topic_rms == "custom/rms"
        assert config.client_id == "custom-client"


class TestServiceConfig:
    """Tests de la configuration complète du service."""

    def test_initialization(self):
        """Test initialisation de la configuration service."""
        config = ServiceConfig()

        assert isinstance(config.audio, AudioConfig)
        assert isinstance(config.vad, VADConfig)
        assert isinstance(config.mqtt, MQTTConfig)
        assert config.log_file == "/opt/Skull/logs/audioin.log"

    def test_nested_config_access(self):
        """Test accès aux configurations imbriquées."""
        config = ServiceConfig()

        # Audio
        assert config.audio.sample_rate == 16000
        assert config.audio.frame_size == 320

        # VAD
        assert config.vad.threshold == 0.3
        assert config.vad.attack_ms == 80

        # MQTT
        assert config.mqtt.host == "127.0.0.1"
        assert config.mqtt.port == 1883

    def test_config_modification(self):
        """Test modification des configurations."""
        config = ServiceConfig()

        # Modifier VAD
        config.vad.threshold = 0.4
        assert config.vad.threshold == 0.4

        # Modifier MQTT
        config.mqtt.host = "remote.example.com"
        assert config.mqtt.host == "remote.example.com"

        # Modifier log
        config.log_file = "/custom/path/audioin.log"
        assert config.log_file == "/custom/path/audioin.log"


class TestConfigIntegration:
    """Tests d'intégration des configurations."""

    def test_vad_config_json_roundtrip(self):
        """Test aller-retour JSON pour VAD config."""
        original = VADConfig(threshold=0.45, attack_ms=75, release_ms=225, eos_ms=900)

        # Config -> JSON -> Config
        json_str = json.dumps(original.to_dict())
        restored = VADConfig.from_json(json_str)

        assert restored.threshold == original.threshold
        assert restored.attack_ms == original.attack_ms
        assert restored.release_ms == original.release_ms
        assert restored.eos_ms == original.eos_ms

    def test_audio_frame_timing(self):
        """Test cohérence temporelle audio."""
        config = AudioConfig()

        # 320 samples à 16kHz = 20ms
        frame_duration_ms = (config.frame_size / config.sample_rate) * 1000
        assert abs(frame_duration_ms - 20.0) < 0.1

    def test_vad_timing_consistency(self):
        """Test cohérence temporelle VAD."""
        vad_config = VADConfig()

        # Les durées doivent être des multiples raisonnables de 20ms
        frame_duration = 20.0

        attack_frames = vad_config.attack_ms / frame_duration
        release_frames = vad_config.release_ms / frame_duration
        eos_frames = vad_config.eos_ms / frame_duration

        # Vérifier que ce sont des nombres entiers ou proches
        assert abs(attack_frames - round(attack_frames)) < 0.1
        assert abs(release_frames - round(release_frames)) < 0.1
        assert abs(eos_frames - round(eos_frames)) < 0.1


@pytest.fixture
def mqtt_config_dict():
    """Configuration MQTT sous forme de dictionnaire."""
    return {
        "host": "test.mosquitto.org",
        "port": 1883,
        "client_id": "test-client",
        "keepalive": 30,
    }


def test_config_from_external_source(mqtt_config_dict):
    """Test configuration depuis source externe."""
    # Simuler chargement depuis fichier/ENV
    config = MQTTConfig(
        host=mqtt_config_dict["host"],
        port=mqtt_config_dict["port"],
        client_id=mqtt_config_dict["client_id"],
        keepalive=mqtt_config_dict["keepalive"],
    )

    assert config.host == "test.mosquitto.org"
    assert config.client_id == "test-client"
    assert config.keepalive == 30
