"""Abstraction des moteurs TTS (backend pluggable).

Deux implementations : Kokoro (rapide, voix preglees -> previews) et Qwen3-TTS
(qualite + clonage par audio de reference -> rendu final). Toutes deux renvoient
de l'audio mono float32 + une frequence d'echantillonnage.
"""
from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import Optional

import numpy as np


@dataclass
class VoiceSpec:
    """Decrit la voix a utiliser pour une synthese.

    - `preset` : nom d'une voix preglee (Kokoro: "ff_siwis" ; Qwen3: "Chelsie").
    - `ref_audio` / `ref_text` : clip de reference pour le clonage (Qwen3).
    """
    preset: Optional[str] = None
    ref_audio: Optional[str] = None
    ref_text: Optional[str] = None
    speed: float = 1.0


class TTSBackend(ABC):
    """Interface commune a tous les moteurs TTS."""

    name: str = "base"

    @abstractmethod
    def synthesize(self, text: str, voice: VoiceSpec) -> tuple[np.ndarray, int]:
        """Synthetise `text` et renvoie (audio mono float32, sample_rate)."""

    def default_voice(self) -> VoiceSpec:
        return VoiceSpec()


def to_mono_float32(audio) -> np.ndarray:
    """Normalise une sortie de modele (mx.array / np / list) en mono float32."""
    arr = np.asarray(audio, dtype=np.float32)
    if arr.ndim > 1:
        # (channels, n) ou (n, channels) -> moyenne sur l'axe des canaux.
        arr = arr.mean(axis=0) if arr.shape[0] < arr.shape[-1] else arr.mean(axis=-1)
    return np.ascontiguousarray(arr.reshape(-1))
