#!/usr/bin/env python3
"""Синтез WAV через те же Kokoro/Piper/eSpeak, которые подключаются к Read Aloud."""
import argparse
import os
import subprocess
import sys
import wave
from pathlib import Path


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("engine", choices=["kokoro", "piper", "espeak"])
    parser.add_argument("text_file", type=Path)
    parser.add_argument("output", type=Path)
    parser.add_argument("--model", type=Path)
    parser.add_argument("--voices", type=Path)
    parser.add_argument("--voice")
    parser.add_argument("--language", default="en-us")
    parser.add_argument("--speed", type=float, default=1.05)
    parser.add_argument("--espeak-bin", default="espeak-ng")
    args = parser.parse_args()
    if args.output.exists():
        parser.error("Файл результата уже существует")
    text = args.text_file.read_text(encoding="utf-8").strip()
    if not text:
        parser.error("Пустой текст")
    if args.engine in {"kokoro", "piper"} and (args.model is None or not args.model.is_file()):
        parser.error("Нужен существующий --model")
    # Создаём выход эксклюзивно; исходный файл и существующие записи не меняются.
    if args.engine == "espeak":
        result = subprocess.run([args.espeak_bin, "--stdout", "-v", args.voice or args.language,
                                 "--stdin"], input=text.encode(), capture_output=True, check=True, timeout=90)
        with args.output.open("xb") as target:
            target.write(result.stdout)
    else:
        os.environ.setdefault("OMP_NUM_THREADS", "2")
        if args.engine == "piper":
            from piper import PiperVoice
            voice = PiperVoice.load(str(args.model))
            with args.output.open("xb") as target, wave.open(target, "wb") as audio:
                voice.synthesize_wav(text, audio)
        else:
            if args.voices is None or not args.voices.is_file():
                parser.error("Нужен существующий --voices")
            from kokoro_onnx import Kokoro
            import numpy as np
            model = Kokoro(str(args.model), str(args.voices))
            samples, rate = model.create(text, voice=args.voice or "bm_george",
                                         lang=args.language, speed=min(1.4, max(.7, args.speed)))
            pcm = (np.clip(samples, -1, 1) * 32767).astype("<i2").tobytes()
            with args.output.open("xb") as target, wave.open(target, "wb") as audio:
                audio.setnchannels(1)
                audio.setsampwidth(2)
                audio.setframerate(rate)
                audio.writeframes(pcm)
    # В отличие от started=true, это проверяет уже созданный файл и непустой сигнал.
    with wave.open(str(args.output), "rb") as audio:
        pcm = audio.readframes(audio.getnframes())
        if not pcm or not any(pcm):
            raise RuntimeError("Получено пустое аудио или цифровая тишина")
        print(f"{args.engine}: {args.output}; {audio.getframerate()} Hz; "
              f"{len(pcm) / (audio.getframerate() * audio.getnchannels() * audio.getsampwidth()):.2f} s")


if __name__ == "__main__":
    try:
        main()
    except (OSError, ValueError, RuntimeError, ImportError, subprocess.SubprocessError) as exc:
        print(f"Local TTS: {exc}", file=sys.stderr)
        raise SystemExit(1)
