"""Service principal Audio-in."""

import logging
import signal
import sys
import time
from typing import Optional

from .audio_capture import AudioCapture, AudioCaptureError
from .config import ServiceConfig, VADConfig
from .logger import setup_logger, log_rms_stats, log_vad_state_change, log_config_update
from .mqtt_client import MQTTAudioClient
from .rms import RMSCalculator
from .vad import VoiceActivityDetector, VADState


class AudioInService:
    """Service principal de capture audio avec VAD et RMS."""

    def __init__(self, config: Optional[ServiceConfig] = None):
        """
        Initialise le service.

        Args:
            config: Configuration du service (None = config par défaut)
        """
        self.config = config or ServiceConfig()
        self.logger = setup_logger(self.config.log_file)
        self.running = False

        # Composants
        self.audio_capture: Optional[AudioCapture] = None
        self.mqtt_client: Optional[MQTTAudioClient] = None
        self.rms_calculator: Optional[RMSCalculator] = None
        self.vad: Optional[VoiceActivityDetector] = None

        # Statistiques
        self.frame_count = 0
        self.last_stats_time = time.time()
        self.stats_interval = 60.0  # Log stats chaque minute

        # Handlers pour arrêt propre
        signal.signal(signal.SIGINT, self._signal_handler)
        signal.signal(signal.SIGTERM, self._signal_handler)

    def _signal_handler(self, signum: int, frame) -> None:
        """Handler pour signaux d'arrêt."""
        self.logger.info(f"Signal reçu: {signum}, arrêt du service...")
        self.stop()

    def _on_config_update(self, new_config: VADConfig) -> None:
        """Callback pour mise à jour config VAD."""
        if self.vad:
            self.vad.update_config(new_config)
            log_config_update(self.logger, new_config.to_dict())

    def _initialize_components(self) -> bool:
        """Initialise tous les composants."""
        try:
            # Audio capture
            self.audio_capture = AudioCapture(self.config.audio)

            # RMS calculator
            self.rms_calculator = RMSCalculator(
                sample_rate=self.config.audio.sample_rate,
                frame_size=self.config.audio.frame_size,
            )

            # VAD
            self.vad = VoiceActivityDetector(
                config=self.config.vad, frame_duration_ms=20.0
            )

            # Client MQTT
            self.mqtt_client = MQTTAudioClient(self.config.mqtt)
            self.mqtt_client.set_config_callback(self._on_config_update)

            self.logger.info("Composants initialisés")
            return True

        except Exception as e:
            self.logger.error(f"Erreur initialisation composants: {e}")
            return False

    def start(self) -> bool:
        """
        Démarre le service.

        Returns:
            True si démarré avec succès
        """
        if self.running:
            self.logger.warning("Service déjà démarré")
            return True

        self.logger.info("Démarrage du service Audio-in...")

        # Initialisation composants
        if not self._initialize_components():
            return False

        # Connexion MQTT
        if not self.mqtt_client.connect(timeout=10.0):
            self.logger.error("Impossible de se connecter à MQTT")
            return False

        # Démarrage capture audio
        try:
            self.audio_capture.start()
        except AudioCaptureError as e:
            self.logger.error(f"Erreur démarrage capture: {e}")
            return False

        self.running = True
        self.logger.info("Service Audio-in démarré")

        return True

    def stop(self) -> None:
        """Arrête le service."""
        if not self.running:
            return

        self.running = False
        self.logger.info("Arrêt du service Audio-in...")

        # Arrêt capture audio
        if self.audio_capture:
            self.audio_capture.stop()

        # Déconnexion MQTT
        if self.mqtt_client:
            self.mqtt_client.disconnect()

        # Stats finales
        if self.vad:
            stats = self.vad.get_stats()
            self.logger.info(f"Statistiques finales: {stats}")

        self.logger.info("Service Audio-in arrêté")

    def _process_audio_frame(self, frame_bytes: bytes) -> None:
        """
        Traite une frame audio.

        Args:
            frame_bytes: Frame audio en bytes
        """
        self.frame_count += 1

        # Calcul RMS
        rms = self.rms_calculator.calculate(frame_bytes)

        # Publication RMS
        self.mqtt_client.publish_rms(rms)

        # Traitement VAD
        vad_result = self.vad.process(rms)

        # Publication VAD
        self.mqtt_client.publish_vad(vad_result)

        # Log changement d'état VAD
        if hasattr(self, "_previous_vad_state"):
            if vad_result.state != self._previous_vad_state:
                log_vad_state_change(self.logger, vad_result.state, rms)

        self._previous_vad_state = vad_result.state

        # Statistiques périodiques
        current_time = time.time()
        if (current_time - self.last_stats_time) >= self.stats_interval:
            self._log_periodic_stats()
            self.last_stats_time = current_time

    def _log_periodic_stats(self) -> None:
        """Log des statistiques périodiques."""
        if not self.vad:
            return

        stats = self.vad.get_stats()
        log_rms_stats(
            self.logger,
            rms_avg=0.0,  # Pas de moyenne RMS maintenue
            active_ratio=stats["active_ratio"],
        )

        # Reset stats pour la prochaine période
        self.vad.reset_stats()

        # Info queue audio
        if self.audio_capture:
            queue_size = self.audio_capture.get_queue_size()
            if queue_size > 10:
                self.logger.warning(f"Queue audio élevée: {queue_size} frames")

    def run(self) -> int:
        """
        Boucle principale du service.

        Returns:
            Code de sortie (0 = succès)
        """
        if not self.start():
            return 1

        try:
            self.logger.info("Boucle principale démarrée")

            # Boucle de traitement
            for frame_bytes in self.audio_capture.get_frames():
                if not self.running:
                    break

                self._process_audio_frame(frame_bytes)

        except KeyboardInterrupt:
            self.logger.info("Interruption clavier")
        except Exception as e:
            self.logger.error(f"Erreur boucle principale: {e}", exc_info=True)
            return 1
        finally:
            self.stop()

        return 0

    def get_status(self) -> dict:
        """Retourne le statut du service."""
        status = {
            "running": self.running,
            "frame_count": self.frame_count,
        }

        if self.mqtt_client:
            status["mqtt_connected"] = self.mqtt_client.is_connected()

        if self.audio_capture:
            status["audio_queue_size"] = self.audio_capture.get_queue_size()

        if self.vad:
            status.update(self.vad.get_stats())

        return status


def create_service(log_file: str = "/opt/Skull/logs/audioin.log") -> AudioInService:
    """Fonction utilitaire pour créer un service."""
    config = ServiceConfig()
    config.log_file = log_file
    return AudioInService(config)


def main() -> int:
    """Point d'entrée principal."""
    service = create_service()
    return service.run()


if __name__ == "__main__":
    sys.exit(main())
