"""Mapping phonèmes vers visèmes pour le français."""

from typing import Dict, List, Optional
import re


class VisemeMapper:
    """Mapper phonèmes eSpeak vers IDs visèmes."""

    # Mapping phonèmes IPA vers IDs visèmes (basé sur formes bouche)
    PHONEME_TO_VISEME: Dict[str, int] = {
        # Voyelles
        "a": 1,  # bouche ouverte
        "e": 2,  # bouche mi-fermée
        "i": 3,  # bouche étirée
        "o": 4,  # bouche arrondie
        "u": 5,  # bouche très arrondie
        "y": 6,  # bouche arrondie + étirée
        # Consonnes labiales (lèvres)
        "p": 7,  # lèvres fermées
        "b": 7,  # lèvres fermées
        "m": 7,  # lèvres fermées
        "f": 8,  # lèvres-dents
        "v": 8,  # lèvres-dents
        # Consonnes dentales/alvéolaires
        "t": 9,  # langue-dents
        "d": 9,  # langue-dents
        "n": 9,  # langue-dents
        "s": 10,  # sifflante
        "z": 10,  # sifflante
        "l": 11,  # langue latérale
        "r": 12,  # roulée
        # Consonnes palatales/vélaires
        "k": 13,  # arrière langue
        "g": 13,  # arrière langue
        "j": 14,  # palatale
        "w": 15,  # labio-vélaire
        # Silence
        "_": 0,  # repos
        " ": 0,  # silence
    }

    # Durées par défaut (ms) selon le type de phonème
    PHONEME_DURATIONS: Dict[str, int] = {
        "voyelle": 120,
        "consonne": 80,
        "silence": 50,
    }

    def __init__(self):
        """Initialise le mapper."""
        self.vowels = {"a", "e", "i", "o", "u", "y"}

    def phoneme_to_viseme_id(self, phoneme: str) -> int:
        """Convertit un phonème en ID visème."""
        # Nettoie le phonème (supprime accents, etc.)
        clean_phoneme = self._clean_phoneme(phoneme)
        return self.PHONEME_TO_VISEME.get(clean_phoneme, 0)

    def get_phoneme_duration(self, phoneme: str, base_duration: int = 100) -> int:
        """Estime la durée d'un phonème."""
        clean_phoneme = self._clean_phoneme(phoneme)

        if clean_phoneme in self.vowels:
            return int(base_duration * 1.2)  # Voyelles plus longues
        elif clean_phoneme in ["_", " "]:
            return self.PHONEME_DURATIONS["silence"]
        else:
            return self.PHONEME_DURATIONS["consonne"]

    def _clean_phoneme(self, phoneme: str) -> str:
        """Nettoie un phonème pour le mapping."""
        # Supprime les annotations eSpeak (chiffres, symboles)
        cleaned = re.sub(r'[0-9\'":]', "", phoneme.lower())

        # Mapping spécifique eSpeak français
        espeak_mapping = {
            "aa": "a",
            "ee": "e",
            "ii": "i",
            "oo": "o",
            "uu": "u",
            "oe": "y",
            "ch": "j",
            "sh": "j",
            "th": "s",
        }

        return espeak_mapping.get(cleaned, cleaned)

    def parse_espeak_phonemes(self, phoneme_text: str) -> List[str]:
        """Parse la sortie phonétique d'eSpeak."""
        if not phoneme_text:
            return []

        # eSpeak sépare les phonèmes par espaces ou tirets
        # Format typique: "s a l y t"
        phonemes = re.findall(r"[a-zA-Z_]+", phoneme_text)
        return [p.strip() for p in phonemes if p.strip()]

    def estimate_word_timing(self, word: str, total_duration_ms: int) -> List[tuple]:
        """Estime le timing des phonèmes dans un mot."""
        # Approximation simple basée sur les syllabes
        syllable_count = len(re.findall(r"[aeiouy]", word.lower()))
        if syllable_count == 0:
            syllable_count = 1

        duration_per_syllable = total_duration_ms // syllable_count

        timings = []
        current_time = 0

        for i in range(syllable_count):
            timings.append((current_time, duration_per_syllable))
            current_time += duration_per_syllable

        return timings
