#!/usr/bin/env python3
"""Genera la misma frase en castellano con las voces masculinas disponibles.

    flatpak run --command=python3 io.github.qwersyk.Newelle//master \
        ~/COFRE/CODERS/JARVIS/config/comparar_voces_es.py

Kokoro solo trae DOS voces masculinas en español: em_alex y em_santa. De los
motores que Newelle soporta, los unicos locales son kokoro y espeak; el resto
—gtts, edge, elevenlabs, openai, groq— son de nube y quedan descartados.

Como ninguna de las dos es especialmente grave, cada una se genera tambien en
version grave: se baja el tono con ffmpeg sin cambiar la velocidad. El truco es
reproducir a menos muestras por segundo (baja tono y alarga) y devolver la
duracion con atempo. A 0.90 baja unos dos semitonos, que se nota sin sonar a
disco rayado; por debajo de 0.85 empieza a sonar artificial.

Se escuchan las cuatro y se fija la elegida con set_voz_es.py.
"""
import os
import subprocess
import sys

sys.path.insert(0, "/app/share/newelle")
sys.path.insert(0, os.path.expanduser(
    "~/.var/app/io.github.qwersyk.Newelle/config/pip"))

from gi.repository import Gio  # noqa: E402

from newelle.handlers.tts.kokoro_handler import KokoroTTSHandler  # noqa: E402
from newelle.handlers.tts.tts import jarvis_audio_filter  # noqa: E402

VOCES = ["em_alex", "em_santa"]
GRAVEDAD = 0.90                     # 1.0 = sin tocar; menos = mas grave
MUESTREO = 24000                    # el que saca kokoro

FRASE = ("Buenas tardes. Todos los sistemas funcionan en local. "
         "La tarjeta grafica esta libre y quedan ochocientos cuarenta y seis "
         "gigabytes en el disco. Quiere que ejecute el diagnostico?")

SALIDA = os.path.expanduser("~/COFRE/CODERS/JARVIS/muestras/voces_es")
CONFIG = os.path.expanduser("~/.var/app/io.github.qwersyk.Newelle/config")


def cadena(grave: bool) -> str:
    """El tratamiento JARVIS, con o sin bajada de tono delante."""
    base = jarvis_audio_filter()
    if not grave:
        return base
    tono = (f"asetrate={int(MUESTREO * GRAVEDAD)},"
            f"aresample={MUESTREO},atempo={1 / GRAVEDAD:.4f}")
    return f"{tono},{base}" if base else tono


def nivel(path):
    """mean/max en dB, para confirmar que ninguna sale floja o recortada."""
    r = subprocess.run(
        ["ffmpeg", "-hide_banner", "-i", path, "-af", "volumedetect",
         "-f", "null", "/dev/null"],
        capture_output=True, text=True,
    )
    vals = [l.split(":")[-1].strip() for l in r.stderr.splitlines()
            if "mean_volume:" in l or "max_volume:" in l]
    return " / ".join(vals) if vals else "?"


def main():
    os.makedirs(SALIDA, exist_ok=True)
    settings = Gio.Settings.new("io.github.qwersyk.Newelle")
    handler = KokoroTTSHandler(settings, os.path.join(CONFIG, "models"))

    if not handler.is_installed():
        print("instalando kokoro...")
        handler.install()

    previa = handler.get_current_voice() if hasattr(handler, "get_current_voice") else None
    print(f"{'fichero':<28} nivel (mean / max)")

    for voz in VOCES:
        handler.set_voice(voz)
        crudo = os.path.join(SALIDA, f"_{voz}.wav")
        try:
            handler.save_audio(FRASE, crudo)
        except Exception as e:
            print(f"{voz:<28} FALLO al generar: {e}")
            continue

        for etiqueta, grave in (("", False), ("_grave", True)):
            final = os.path.join(SALIDA, f"{voz}{etiqueta}.wav")
            try:
                subprocess.run(
                    ["ffmpeg", "-hide_banner", "-loglevel", "error",
                     "-i", crudo, "-af", cadena(grave), "-y", final],
                    check=True,
                )
                print(f"{os.path.basename(final):<28} {nivel(final)}")
            except Exception as e:
                print(f"{voz}{etiqueta:<20} FALLO: {e}")
        os.remove(crudo)

    if previa:
        handler.set_voice(previa)
    print(f"\nescuchalas en: {SALIDA}")
    print("la elegida se fija con set_voz_es.py <voz> [--grave]")
    return 0


if __name__ == "__main__":
    sys.exit(main())
