#!/usr/bin/env python3
"""
Klimawächter SFX-Generator für ElevenLabs Sound Effects API.

Liest App/.env.local (ELEVENLABS_API_KEY) + sounds-list.json und lädt für
jeden Eintrag einen MP3 von ElevenLabs in ../assets/sounds/. Existierende
Dateien werden übersprungen (für inkrementelles Laufenlassen).

Aufruf:
  cd App/sims/klima/scripts
  python generate-sounds.py            # alle fehlenden Sounds generieren
  python generate-sounds.py --force    # ALLE neu generieren (überschreibt)
  python generate-sounds.py ui-click   # nur diesen einen Sound
"""

import json
import os
import sys
import time
import urllib.request
import urllib.error
from pathlib import Path

API_URL = "https://api.elevenlabs.io/v1/sound-generation"
SCRIPT_DIR = Path(__file__).resolve().parent
SOUNDS_LIST = SCRIPT_DIR / "sounds-list.json"
OUT_DIR = SCRIPT_DIR.parent / "assets" / "sounds"
APP_ROOT = SCRIPT_DIR.parent.parent.parent  # App/
ENV_FILE = APP_ROOT / ".env.local"


def load_env(file_path: Path) -> dict:
    env = {}
    if not file_path.exists():
        return env
    for line in file_path.read_text(encoding="utf-8").splitlines():
        line = line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, _, val = line.partition("=")
        env[key.strip()] = val.strip()
    return env


def generate_sound(api_key: str, prompt: str, duration: float, influence: float) -> bytes:
    body = json.dumps({
        "text": prompt,
        "duration_seconds": duration,
        "prompt_influence": influence,
    }).encode("utf-8")
    req = urllib.request.Request(
        API_URL,
        data=body,
        method="POST",
        headers={
            "xi-api-key": api_key,
            "Content-Type": "application/json",
            "Accept": "audio/mpeg",
        },
    )
    with urllib.request.urlopen(req, timeout=120) as resp:
        return resp.read()


def main() -> int:
    env = load_env(ENV_FILE)
    api_key = env.get("ELEVENLABS_API_KEY") or os.environ.get("ELEVENLABS_API_KEY")
    if not api_key:
        print(f"FEHLER: ELEVENLABS_API_KEY nicht in {ENV_FILE} oder Umgebung gefunden.", file=sys.stderr)
        return 1

    force = "--force" in sys.argv
    only_file = None
    for arg in sys.argv[1:]:
        if arg.startswith("--"):
            continue
        only_file = arg + ".mp3" if not arg.endswith(".mp3") else arg
        break

    data = json.loads(SOUNDS_LIST.read_text(encoding="utf-8"))
    sounds = data["sounds"]
    OUT_DIR.mkdir(parents=True, exist_ok=True)

    total = len(sounds)
    generated = 0
    skipped = 0
    errors = 0

    for i, s in enumerate(sounds, 1):
        name = s["file"]
        out = OUT_DIR / name
        if only_file and name != only_file:
            continue
        if out.exists() and not force:
            skipped += 1
            print(f"[{i:2}/{total}] SKIP {name:28} (schon da, --force überschreibt)")
            continue

        prompt = s["prompt"]
        dur = float(s.get("duration", 2.0))
        infl = float(s.get("influence", 0.5))
        print(f"[{i:2}/{total}] GEN  {name:28} dur={dur}s  → {prompt[:60]}…")
        try:
            audio = generate_sound(api_key, prompt, dur, infl)
            out.write_bytes(audio)
            generated += 1
            # ElevenLabs verlangt keine Rate-Limit-Pause, aber 0,5s Pause
            # reduziert Last und macht Fehler besser lesbar.
            time.sleep(0.5)
        except urllib.error.HTTPError as e:
            msg = e.read().decode("utf-8", errors="ignore")[:200]
            print(f"    HTTP {e.code}: {msg}", file=sys.stderr)
            errors += 1
        except Exception as e:
            print(f"    Fehler: {e}", file=sys.stderr)
            errors += 1

    print()
    print(f"Ergebnis: {generated} neu, {skipped} übersprungen, {errors} Fehler")
    print(f"Zielordner: {OUT_DIR}")
    return 0 if errors == 0 else 1


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