#!/usr/bin/env python3
"""
Etappe 0: Legacy-Audios aus start.html / landing.html in den Standard ziehen.

Aktionen:
  1) Bestehende Motivations-Phrasen in r_tower_strike_c* + r_tower_handover_c* säubern
  2) Neue Eintraege in audio-texts.json fuer LEGACY-Audio-IDs (ohne r_-Praefix)
  3) Regenerieren aller betroffenen MP3s (mit r_-Praefix damit playRadio-Fallback greift)

Texte: kurz, Pilot/Tower-Funk-Stil, KEIN "Christophorus", KEIN "ÖAMTC",
       KEINE Motivations-Phrasen wie "du kriegst das hin / du schaffst das".
"""
import json, os, sys, subprocess, tempfile, shutil, time

KEY = os.environ.get('ELEVENLABS_API_KEY') or 'sk_8e21b8c2723d95fc581953c1d0fff9af3e1298faa378a651'
REPO = 'C:/xampp/htdocs/geograsim/App/sims/heli'
OUT_DIR = REPO + '/sounds/radio'
TEXTS_FILE = REPO + '/scripts/audio-texts.json'
MAP_FILE = REPO + '/data/aussprache-map.json'
DUR_FILE = REPO + '/data/audio-durations.json'

VOICE_SARAH = 'EXAVITQu4vr4xnSDxMaL'  # Tower-Lotsin
VOICE_BELLA = 'hpp4J3VqNfWAUOO0d1Us'  # Pilotin

# === 1) Motivations-Phrasen-Fixes (bestehende r_-Eintraege updaten) ===
MOTIVATION_FIXES = {
    # r_tower_strike_c* — alle 14 Eintraege ersetzen die Phrase
    '_strike_motivation': {
        'old': ', du kriegst das hin.',
        'new': ', noch zwei Versuche frei.',
        'pattern_prefix': 'r_tower_strike_c',
    },
    '_handover_motivation': {
        'old': ' Alles gut, du lernst dazu.',
        'new': '',
        'pattern_prefix': 'r_tower_handover_c',
    },
}

# === 2) Neue Eintraege fuer LEGACY-Audio-IDs ===
# Naming convention: ID -> (text, voice_label, ist_pilotin)
# 'b' = Bella (Pilotin), 's' = Sarah (Tower-Lotsin)
NEW_TEXTS = {
    # --- Pilot Calm (Wetter ok, gute Verhältnisse) ---
    'r_pilot_calm1': ('Pilot: Wetterlage stabil. Sichtflug-Bedingungen, top. Standby.', 'b'),
    'r_pilot_calm2': ('Pilot: Wind aus Nordwest, drei Beaufort. Kein Drama für den Kurs.', 'b'),
    'r_pilot_calm3': ('Pilot: Sicht über fünfzehn Kilometer — wir sehen alles. Roger.', 'b'),

    # --- Pilot Hindernisse / Strecke (preventive Tipps) ---
    'r_pilot_flock':  ('Pilot: Vogelschwarm von West. Kurs anpassen, easy.', 'b'),
    'r_pilot_fog1':   ('Pilot: Advektionsnebel unten. Sicht unter fünfhundert Meter. Tief bleiben.', 'b'),
    'r_pilot_fog2':   ('Pilot: Referenzpunkt am Boden suchen — nicht am Horizont.', 'b'),
    'r_pilot_fog3':   ('Pilot: Lageregelung flach halten, nicht blind in die Wolke. Copy?', 'b'),
    'r_pilot_gap':    ('Pilot: Urbaner Canyon. Über Dachkante bleiben. Roger.', 'b'),
    'r_pilot_gusts':  ('Pilot: Lee-Turbulenz zwischen den Häusern — Anstellwinkel nachfassen.', 'b'),
    'r_pilot_narrow': ('Pilot: Talenge voraus, Venturi-Effekt. Windseite halten. Over.', 'b'),
    'r_pilot_time':   ('Pilot: Thermik über den Hallen — Aufwinde, Achtung.', 'b'),
    'r_pilot_trees':  ('Pilot: Fichten bis fünfundzwanzig Meter — Puffer halten. Copy.', 'b'),
    'r_pilot_wind':   ('Pilot: Windwurf im Tal — Böen drehen. Vorsicht.', 'b'),

    # --- Warn (Pre-Warn fuer Hindernisse) ---
    'r_warn_kran':         ('Pilot: Kran rechts, vierzig Meter. Mindestabstand halten.', 'b'),
    'r_warn_antenne':      ('Pilot: Antenne links, einhundertzwanzig Meter hoch. Umfliegen mit Puffer.', 'b'),
    'r_warn_strom':        ('Pilot: Hochspannungsleitung voraus. Drüber, nicht drunter. Roger.', 'b'),
    'r_warn_schornstein':  ('Pilot: Schornsteine als Festpunkte nutzen — visuelle Referenz.', 'b'),
    'r_warn_fabrik':       ('Pilot: Abwindzone links. Höher und nach rechts.', 'b'),
    'r_warn_nebel':        ('Pilot: Nebel dichtet ein. Kurs halten — vorsichtig.', 'b'),
    'r_warn_gewitter':     ('Pilot: Gewitterzelle voraus, sieben Meilen. Umfliegen.', 'b'),
    'r_warn_fuel':         ('Pilot: Treibstoff knapp. Klinikkurs halten.', 'b'),

    # --- Warn (Crash-Reaction — wird nach Strike gespielt) ---
    'r_warn_vogel':    ('Pilot: Vogelschlag! Rotor checken.', 'b'),
    'r_warn_haus':     ('Pilot: Gebäude touchiert. Schaden auswerten.', 'b'),
    'r_warn_baum':     ('Pilot: Baum gestreift. Höhe rauf.', 'b'),
    'r_warn_klima':    ('Pilot: Klimaanlage gerissen. Abstand halten.', 'b'),
    'r_warn_blitz':    ('Pilot: Blitz nahe! Sofort raus aus der Zelle.', 'b'),
    'r_warn_flugzeug': ('Pilot: Verkehrsflugzeug! Sofort tiefer.', 'b'),
    'r_warn_sport':    ('Pilot: Sportflieger im Kurs! Ausweichen.', 'b'),

    # --- Tower generic (kein Heli-Name) ---
    'r_tower1': ('Tower: Pilot, Flugplan bestätigt. Position halten, Freigabe folgt.', 's'),
    'r_tower2': ('Tower: Wind im Rahmen. Sektor klar, weiter im Plan.', 's'),
    'r_tower3': ('Tower: Sektor frei. Anflugkorridor ist offen.', 's'),
    'r_tower4': ('Tower: Frequenz wechseln. Standby auf neuer Sektor-Freigabe.', 's'),

    # --- Success (V2-Backup, normalerweise von V1 geblockt) ---
    'r_success2': ('Tower: Sauber abgefangen. Mission steht.', 's'),
}

def apply_pron(text, mapping):
    for k in sorted(mapping.keys(), key=len, reverse=True):
        text = text.replace(k, mapping[k])
    return text

def generate(aid, text, voice_id):
    out = OUT_DIR + '/' + aid + '.mp3'
    if os.path.exists(out):
        shutil.copy(out, out + '.bak-pre-etappe0')
    body = json.dumps({
        'text': text, 'model_id': 'eleven_multilingual_v2',
        'voice_settings': {'stability': 0.55, 'similarity_boost': 0.75, 'style': 0.1, 'use_speaker_boost': True}
    }, ensure_ascii=False)
    with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.json', delete=False) as f:
        f.write(body); bpath = f.name
    r = subprocess.run(['curl','-sS','-w','%{http_code}','-o',out,
        '-X','POST','https://api.elevenlabs.io/v1/text-to-speech/' + voice_id,
        '-H','xi-api-key: ' + KEY,
        '-H','Content-Type: application/json; charset=utf-8',
        '--data-binary','@' + bpath], capture_output=True, text=True, timeout=120)
    os.unlink(bpath)
    return ('ok' if r.stdout.strip() == '200' else 'err-' + r.stdout), os.path.getsize(out) if os.path.exists(out) else 0

def main():
    texts = json.load(open(TEXTS_FILE, 'r', encoding='utf-8'))
    pron = json.load(open(MAP_FILE, 'r', encoding='utf-8'))['pronunciations']
    durs = json.load(open(DUR_FILE, 'r', encoding='utf-8'))

    # === Schritt 1: Motivations-Phrasen-Fixes ===
    print('=== Schritt 1: Motivations-Phrasen-Fixes ===')
    motivation_changed = []
    for fix in MOTIVATION_FIXES.values():
        for aid, txt in list(texts.items()):
            if isinstance(txt, str) and aid.startswith(fix['pattern_prefix']):
                if fix['old'] in txt:
                    texts[aid] = txt.replace(fix['old'], fix['new'])
                    motivation_changed.append(aid)
    print(f'  {len(motivation_changed)} Eintraege gefixt')

    # === Schritt 2: Neue Eintraege importieren ===
    print('\n=== Schritt 2: Neue Eintraege ===')
    for aid, (txt, voice) in NEW_TEXTS.items():
        texts[aid] = txt
    print(f'  {len(NEW_TEXTS)} neue Eintraege')

    # Speichern
    with open(TEXTS_FILE, 'w', encoding='utf-8') as f:
        json.dump(texts, f, indent=2, ensure_ascii=False)
    print(f'\n  -> audio-texts.json gespeichert ({len(texts)} Eintraege total)')

    if '--dry' in sys.argv:
        print('\n--dry-run, keine MP3s generiert.')
        return

    # === Schritt 3: Regen ===
    print('\n=== Schritt 3: Regen-Lauf ===')
    regen_list = motivation_changed + list(NEW_TEXTS.keys())
    print(f'  Total: {len(regen_list)} MP3s')
    print()

    t0 = time.time()
    ok, fail = 0, 0
    for i, aid in enumerate(regen_list, 1):
        text = texts[aid]
        tts = apply_pron(text, pron)
        # Voice-Routing
        if aid in NEW_TEXTS:
            voice = VOICE_BELLA if NEW_TEXTS[aid][1] == 'b' else VOICE_SARAH
            label = 'Bella' if NEW_TEXTS[aid][1] == 'b' else 'Sarah'
        elif aid.startswith('r_tower_'):
            voice = VOICE_SARAH; label = 'Sarah'
        else:
            voice = VOICE_BELLA; label = 'Bella'
        status, size = generate(aid, tts, voice)
        elapsed = time.time() - t0
        eta = (elapsed / i) * (len(regen_list) - i)
        if status == 'ok':
            print(f'  [{i:2d}/{len(regen_list)}] OK  {aid:38s} {size//1024:>4}K [{label}]  ETA {eta:.0f}s')
            ok += 1
            durs['durations'].pop(aid, None)
        else:
            print(f'  [{i:2d}/{len(regen_list)}] ERR {aid:38s} {status}')
            fail += 1
        if i % 10 == 0:
            json.dump(durs, open(DUR_FILE, 'w', encoding='utf-8'), indent=2, ensure_ascii=False)

    json.dump(durs, open(DUR_FILE, 'w', encoding='utf-8'), indent=2, ensure_ascii=False)
    print(f'\nFertig: {ok} OK, {fail} Fehler, {time.time()-t0:.0f}s')

if __name__ == '__main__':
    main()
