"""Generate optional prerecorded narration; never put API keys in browser code."""
import os
import re
import tempfile
from pathlib import Path
import json
from urllib.request import Request, urlopen
from urllib.error import HTTPError, URLError

BASE_URL = 'https://api.elevenlabs.io/v1'
AUDIO_DIR = Path(__file__).resolve().parent / 'static' / 'audio'

class ElevenLabsVoiceEngine:
    def __init__(self):
        self.api_key = os.environ.get('ELEVENLABS_API_KEY')
        if not self.api_key:
            raise ValueError('Set ELEVENLABS_API_KEY in your local environment.')
        self.model = os.environ.get('ELEVENLABS_MODEL_ID', 'eleven_multilingual_v2')

    def generate_voice_file(self, voice_id: str, script_text: str, filename: str) -> str:
        if not re.fullmatch(r'[A-Za-z0-9_-]{1,128}', voice_id or ''):
            raise ValueError('A valid ELEVENLABS_VOICE_ID is required.')
        if not re.fullmatch(r'[A-Za-z0-9_-]+\.mp3', filename):
            raise ValueError('Filename must be a plain MP3 basename.')
        if not script_text.strip() or len(script_text) > 5000:
            raise ValueError('Script must contain 1–5000 characters.')
        payload = {'text': script_text, 'model_id': self.model,
                   'voice_settings': {'stability': .72, 'similarity_boost': .88}}
        request = Request(
            f'{BASE_URL}/text-to-speech/{voice_id}?output_format=mp3_44100_128',
            data=json.dumps(payload).encode(), method='POST',
            headers={'xi-api-key': self.api_key, 'Content-Type': 'application/json', 'Accept': 'audio/mpeg'})
        try:
            with urlopen(request, timeout=60) as response:
                content_type = response.headers.get('Content-Type', '').lower()
                content = response.read()
                if response.status != 200 or 'audio/' not in content_type or not content:
                    raise RuntimeError('Voice service did not return audio; existing audio was preserved.')
        except HTTPError as exc:
            raise RuntimeError(f'Voice synthesis failed (HTTP {exc.code}); existing audio was preserved.') from None
        except (URLError, TimeoutError, OSError):
            raise RuntimeError('Voice service could not be reached; existing audio was preserved.') from None
        AUDIO_DIR.mkdir(parents=True, exist_ok=True)
        path = AUDIO_DIR / filename
        tmp = None
        try:
            with tempfile.NamedTemporaryFile(dir=AUDIO_DIR, suffix='.tmp', delete=False) as f:
                tmp = Path(f.name)
                f.write(content)
            tmp.replace(path)
        finally:
            if tmp and tmp.exists():
                tmp.unlink()
        return str(path)

if __name__ == '__main__':
    voice_id = os.environ.get('ELEVENLABS_VOICE_ID')
    if not voice_id:
        raise SystemExit('Set ELEVENLABS_VOICE_ID to an existing voice you are authorized to use.')
    try:
        engine = ElevenLabsVoiceEngine()
        scripts = {
            'cloned_qzotic_arrival.mp3': 'Welcome, funky intellectual passengers. We have arrived at Gliese 581. The worlds and station outside are artistic reconstructions. Settle into Saturday Lounge as we begin our orbital cruise.',
            'cloned_qzotic_return.mp3': 'Attention, funky intellectual passengers. The pilot has begun our return to Earth. Enjoy the music as we travel home. Atmospheric reentry will follow when we reach Earth.',
        }
        for filename, text in scripts.items():
            print(engine.generate_voice_file(voice_id, text, filename))
    except (ValueError, RuntimeError) as exc:
        raise SystemExit(str(exc)) from None
