"""Fließendes Deutsch (Edge Neural) – Text wird wirklich gesprochen."""

from __future__ import annotations

import asyncio
import os
import re
import time
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
VOICE_DIR = ROOT / "assets" / "voice"
LOG_FILE = ROOT / "data" / "jam-voice.log"

# Native deutsche Neural-Stimmen – Hochdeutsch ohne Fremdakzent
FLUENT_VOICES = (
    "de-DE-KatjaNeural",
    "de-DE-ConradNeural",
    "de-DE-AmalaNeural",
    "de-DE-KillianNeural",
)

CHARACTER_VOICES = (
    "de-DE-KillianNeural",
    "de-DE-ConradNeural",
)

_SENT_SPLIT = re.compile(r"(?<=[.!?…])\s+")


def _log(msg: str) -> None:
    try:
        LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
        with LOG_FILE.open("a", encoding="utf-8") as f:
            f.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {msg}\n")
    except OSError:
        pass


def tts_mode() -> str:
    """fluent (Standard) | character | creature"""
    return os.environ.get("JAM_TTS", "fluent").strip().lower() or "fluent"


def is_creature_only_line(text: str) -> bool:
    """Nur Geräusch, kein echter Satz – da reicht MP3/SFX."""
    t = text.strip()
    if not t or len(t) > 14:
        return False
    if t.startswith("*") and t.endswith("*"):
        return True
    return t.lower() in {"piep", "boop", "mrrp", "blub", "♪", "♪ ♪"}


def prepare_german_text(text: str, *, max_chars: int | None = 220) -> str:
    """Text für natürliche Aussprache vorbereiten."""
    t = text.strip()
    t = re.sub(r"\*+", "", t)
    t = re.sub(r"[💭💨😈🎮🔊👾🍪📚🎵💃👍👎]", "", t)
    t = t.replace("…", ".")
    t = re.sub(r"\s+", " ", t).strip()
    if not t:
        return "Jam."

    # CHEATEST / SCHEISSE → lesbarer Satz für TTS
    t = re.sub(r"\bCHEAT\w*\b", lambda m: m.group(0).lower(), t, flags=re.I)
    t = re.sub(r"\bSCHEISSE\b", "scheiße", t, flags=re.I)

    if max_chars and len(t) > max_chars:
        t = t[: max_chars - 3].rsplit(" ", 1)[0] + "…"

    if t[-1] not in ".!?":
        t += "."
    return t


def _pick_voice(*, character: bool) -> str:
    custom = os.environ.get("JAM_TTS_VOICE", "").strip()
    if custom:
        return custom
    pool = CHARACTER_VOICES if character else FLUENT_VOICES
    import random

    return random.choice(pool)


def _prosody(
    stage: int, loud: bool, *, character: bool, very_loud: bool = False
) -> tuple[str, str, str]:
    if very_loud:
        rate = "+28%"
        pitch = "+8Hz"
        vol = "+24%"
    elif character:
        rate = "+12%" if loud else "+4%"
        pitch = "-22Hz" if loud else "-14Hz"
        vol = "+14%" if loud else "+6%"
    else:
        # Fließend, leicht expressiv
        if loud:
            rate = "+6%"
            pitch = "-6Hz"
            vol = "+12%"
        elif stage <= 0:
            rate = "+8%"
            pitch = "+4Hz"
            vol = "+8%"
        else:
            rate = "-2%"
            pitch = "-4Hz"
            vol = "+6%"
    return rate, pitch, vol


def _sentences(text: str) -> list[str]:
    parts = [p.strip() for p in _SENT_SPLIT.split(text) if p.strip()]
    return parts or [text]


def speak_edge_fluent(
    text: str,
    stage: int = 1,
    loud: bool = False,
    *,
    character: bool = False,
    very_loud: bool = False,
    play_fn,
) -> bool:
    """Synthese + Wiedergabe über play_fn(path, volume_percent)."""
    try:
        import edge_tts
    except ImportError:
        _log("edge-tts missing")
        return False

    clean = prepare_german_text(text)
    voice = _pick_voice(character=character)
    rate, pitch, vol = _prosody(
        stage, loud, character=character, very_loud=very_loud
    )
    VOICE_DIR.mkdir(parents=True, exist_ok=True)
    tmp = VOICE_DIR / "_live_de.mp3"
    vol_pct = 100 if (loud or very_loud) else 92

    any_ok = False
    for i, sentence in enumerate(_sentences(clean)):
        try:
            comm = edge_tts.Communicate(
                sentence,
                voice,
                rate=rate,
                pitch=pitch,
                volume=vol,
            )
            loop = asyncio.new_event_loop()
            try:
                asyncio.set_event_loop(loop)
                loop.run_until_complete(comm.save(str(tmp)))
            finally:
                loop.close()
                asyncio.set_event_loop(None)
            time.sleep(0.04)
            if tmp.exists() and tmp.stat().st_size > 200:
                if play_fn(tmp, vol_pct):
                    any_ok = True
            if i < len(_sentences(clean)) - 1:
                time.sleep(0.14)
        except Exception as e:
            _log(f"edge sentence failed: {e}")
    return any_ok
