#!/usr/bin/env python3
"""
AIVA Demo Recording Script
Generates hero page voiceover using Telnyx TTS API with AIVA's voice (eucalyptus)

Usage:
    python record_demo.py

Output:
    /mnt/e/genesis-system/RECEPTIONISTAI/assets/audio/demo.opus (primary)
    /mnt/e/genesis-system/RECEPTIONISTAI/assets/audio/demo.mp3 (fallback)

Author: Genesis AI
Created: 2026-02-15
"""

import os
import sys
import json
import subprocess
from pathlib import Path
import requests
from docx import Document

# ============================================================================
# CONFIGURATION
# ============================================================================

TELNYX_API_KEY = "KEY019BE7A3A2D749FCA8681CFF8448A7F0_vTMM1n77CtQxLDT2ra3P1z"
TELNYX_TTS_URL = "https://api.telnyx.com/v2/text-to-speech"
VOICE_NAME = "eucalyptus"  # AIVA's voice (Australian Female Premium HD)

# Paths
REPO_ROOT = Path("/mnt/e/genesis-system")
SCRIPT_DOCX = REPO_ROOT / "RECEPTIONISTAI" / "Receptionist AI Pre-Recording Demo Script.docx"
OUTPUT_DIR = REPO_ROOT / "RECEPTIONISTAI" / "assets" / "audio"

# Audio settings
SAMPLE_RATE = 22050  # 22.05kHz (optimal for speech)
OPUS_BITRATE = "32k"  # Low bitrate, high quality for speech
MP3_BITRATE = "48k"   # Fallback bitrate

# ============================================================================
# SCRIPT TEXT (fallback if docx read fails)
# ============================================================================

FALLBACK_SCRIPT = """Hello, I'm Maya from Receptionist AI, and I'm about to become your new receptionist. But here's something you should know upfront - I'm not a real person. I'm an AI voice agent, though I bet I sound pretty convincing, right?

Let me show you what I actually do. Every single day, I answer your business phones around the clock - morning calls, evening inquiries, even 3am emergencies. I never take a sick day, never go on holiday, and I'm never too busy to pick up.

When someone rings asking about your services, I've got the answers. Pricing questions? Handled. Booking an appointment? Done and confirmed. Want to know your opening hours or location? I've got it covered.

But here's where it gets interesting: after every conversation, I immediately text and email them a summary of what we discussed. Confirmation details, next steps, everything they need. No delays, no forgetting to follow up.

I can do something else that's pretty powerful - I'll work through your contact list and reconnect with people who showed interest months ago but never booked. Old quotes, abandoned inquiries, dead leads - I bring them back to life.

Want proof this works? I recently handled one business's phones for a day and secured 30 confirmed bookings before dinner time. Appointments they would've completely missed otherwise.

And it gets even better. I learn from every single interaction. Each conversation makes me smarter and more capable at understanding your customers and getting them to say yes.

Ready to see how I'd sound talking about YOUR specific business? Enter your website address below and I'll call you in the next 30 seconds with a personalized demonstration. You'll hear me discuss your actual services, your location, everything - like I'm already working for you.

Go ahead, enter your details. Let's see what I can do for your business."""


# ============================================================================
# HELPER FUNCTIONS
# ============================================================================

def setup_output_directory():
    """Create output directory if it doesn't exist."""
    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    print(f"✅ Output directory ready: {OUTPUT_DIR}")


def read_script_from_docx():
    """
    Extract script text from the .docx file.
    Returns the script text or None if reading fails.
    """
    try:
        print(f"📖 Reading script from: {SCRIPT_DOCX}")
        doc = Document(str(SCRIPT_DOCX))

        # Extract all paragraph text
        paragraphs = [p.text.strip() for p in doc.paragraphs if p.text.strip()]

        # Skip title (first line) and combine the rest
        if len(paragraphs) > 1:
            script_text = "\n\n".join(paragraphs[1:])  # Skip title
        else:
            script_text = "\n\n".join(paragraphs)

        print(f"✅ Script loaded ({len(script_text)} characters)")
        return script_text

    except Exception as e:
        print(f"⚠️  Failed to read docx: {e}")
        print("   Using fallback script text")
        return None


def call_telnyx_tts(text):
    """
    Call Telnyx TTS API to generate audio.
    Returns the audio data (bytes) or None on failure.
    """
    print(f"\n🎙️  Calling Telnyx TTS API...")
    print(f"   Voice: {VOICE_NAME}")
    print(f"   Text length: {len(text)} characters")

    headers = {
        "Authorization": f"Bearer {TELNYX_API_KEY}",
        "Content-Type": "application/json"
    }

    payload = {
        "voice": VOICE_NAME,
        "text": text,
        "audio_format": "wav",
        "sample_rate": SAMPLE_RATE
    }

    try:
        response = requests.post(
            TELNYX_TTS_URL,
            headers=headers,
            json=payload,
            timeout=60  # 60 second timeout
        )

        if response.status_code == 200:
            print(f"✅ TTS generation successful")
            print(f"   Audio size: {len(response.content) / 1024:.1f} KB")
            return response.content
        else:
            print(f"❌ TTS API error: {response.status_code}")
            print(f"   Response: {response.text}")
            return None

    except Exception as e:
        print(f"❌ TTS request failed: {e}")
        return None


def save_audio_file(audio_data, filename):
    """Save audio data to a file."""
    filepath = OUTPUT_DIR / filename

    try:
        with open(filepath, 'wb') as f:
            f.write(audio_data)
        print(f"✅ Saved: {filepath}")
        return filepath
    except Exception as e:
        print(f"❌ Failed to save {filename}: {e}")
        return None


def run_ffmpeg_command(command, description):
    """
    Run an ffmpeg command and handle errors.
    Returns True on success, False on failure.
    """
    print(f"\n🔧 {description}...")
    print(f"   Command: {' '.join(command)}")

    try:
        result = subprocess.run(
            command,
            capture_output=True,
            text=True,
            check=True
        )
        print(f"✅ {description} complete")
        return True

    except subprocess.CalledProcessError as e:
        print(f"❌ {description} failed")
        print(f"   Error: {e.stderr}")
        return False
    except FileNotFoundError:
        print(f"❌ ffmpeg not found. Please install ffmpeg:")
        print(f"   Ubuntu/WSL: sudo apt-get install ffmpeg")
        print(f"   macOS: brew install ffmpeg")
        return False


def normalize_audio(input_file, output_file):
    """Normalize audio volume to -16 LUFS (web standard)."""
    command = [
        "ffmpeg", "-y",
        "-i", str(input_file),
        "-af", "loudnorm=I=-16:TP=-1.5:LRA=11",
        str(output_file)
    ]
    return run_ffmpeg_command(command, "Normalizing volume")


def trim_silence(input_file, output_file):
    """Remove leading and trailing silence."""
    command = [
        "ffmpeg", "-y",
        "-i", str(input_file),
        "-af", (
            "silenceremove=start_periods=1:start_silence=0.1:start_threshold=-50dB,"
            "areverse,"
            "silenceremove=start_periods=1:start_silence=0.1:start_threshold=-50dB,"
            "areverse"
        ),
        str(output_file)
    ]
    return run_ffmpeg_command(command, "Trimming silence")


def convert_to_opus(input_file, output_file):
    """Convert to WebM/Opus format (optimized for web)."""
    command = [
        "ffmpeg", "-y",
        "-i", str(input_file),
        "-c:a", "libopus",
        "-b:a", OPUS_BITRATE,
        "-vbr", "on",
        "-compression_level", "10",
        str(output_file)
    ]
    return run_ffmpeg_command(command, "Converting to WebM/Opus")


def convert_to_mp3(input_file, output_file):
    """Convert to MP3 format (fallback for older browsers)."""
    command = [
        "ffmpeg", "-y",
        "-i", str(input_file),
        "-c:a", "libmp3lame",
        "-b:a", MP3_BITRATE,
        "-ac", "1",  # Mono
        "-ar", str(SAMPLE_RATE),
        str(output_file)
    ]
    return run_ffmpeg_command(command, "Converting to MP3")


def get_audio_duration(audio_file):
    """Get duration of audio file using ffprobe."""
    try:
        command = [
            "ffprobe", "-v", "error",
            "-show_entries", "format=duration",
            "-of", "default=noprint_wrappers=1:nokey=1",
            str(audio_file)
        ]
        result = subprocess.run(command, capture_output=True, text=True, check=True)
        duration = float(result.stdout.strip())
        return duration
    except Exception as e:
        print(f"⚠️  Could not get duration: {e}")
        return None


def verify_output_files():
    """Verify the final output files meet requirements."""
    print("\n" + "="*70)
    print("VERIFICATION REPORT")
    print("="*70)

    opus_file = OUTPUT_DIR / "demo.opus"
    mp3_file = OUTPUT_DIR / "demo.mp3"

    all_good = True

    # Check Opus file
    if opus_file.exists():
        opus_size = opus_file.stat().st_size / 1024  # KB
        opus_duration = get_audio_duration(opus_file)

        print(f"\n📦 WebM/Opus (Primary)")
        print(f"   File: {opus_file.name}")
        print(f"   Size: {opus_size:.1f} KB {'✅' if opus_size < 350 else '⚠️  (>350KB)'}")
        print(f"   Duration: {opus_duration:.1f}s" if opus_duration else "   Duration: Unknown")

        if opus_size > 350:
            all_good = False
    else:
        print(f"\n❌ WebM/Opus file not found")
        all_good = False

    # Check MP3 file
    if mp3_file.exists():
        mp3_size = mp3_file.stat().st_size / 1024  # KB
        mp3_duration = get_audio_duration(mp3_file)

        print(f"\n📦 MP3 (Fallback)")
        print(f"   File: {mp3_file.name}")
        print(f"   Size: {mp3_size:.1f} KB {'✅' if mp3_size < 500 else '⚠️  (>500KB)'}")
        print(f"   Duration: {mp3_duration:.1f}s" if mp3_duration else "   Duration: Unknown")

        if mp3_size > 500:
            all_good = False
    else:
        print(f"\n❌ MP3 file not found")
        all_good = False

    print("\n" + "="*70)

    if all_good:
        print("✅ ALL CHECKS PASSED - Ready for deployment")
    else:
        print("⚠️  Some checks failed - review output above")

    print("="*70)

    return all_good


def print_next_steps():
    """Print deployment instructions."""
    print("\n" + "="*70)
    print("NEXT STEPS")
    print("="*70)
    print("""
1. Listen to the generated audio files:
   - {}/demo.opus (primary)
   - {}/demo.mp3 (fallback)

2. If satisfied, deploy to website:
   - Upload both files to website assets folder
   - Update hero video HTML:

     <audio>
       <source src="/assets/audio/demo.opus" type="audio/webm; codecs=opus">
       <source src="/assets/audio/demo.mp3" type="audio/mpeg">
     </audio>

3. Test on multiple browsers:
   - Chrome (Opus)
   - Firefox (Opus)
   - Safari (Opus/MP3)
   - Edge (Opus)
   - Mobile (iOS + Android)

4. Monitor performance:
   - Check loading time (<2s on 3G)
   - Verify autoplay behavior
   - Track engagement metrics
""".format(OUTPUT_DIR, OUTPUT_DIR))
    print("="*70 + "\n")


# ============================================================================
# MAIN EXECUTION
# ============================================================================

def main():
    """Main execution flow."""
    print("\n" + "="*70)
    print("AIVA DEMO RECORDING SCRIPT")
    print("="*70)
    print(f"Voice: {VOICE_NAME} (AIVA - Australian Female Premium HD)")
    print(f"Output: {OUTPUT_DIR}")
    print("="*70 + "\n")

    # Step 1: Setup
    setup_output_directory()

    # Step 2: Read script
    script_text = read_script_from_docx()
    if script_text is None:
        script_text = FALLBACK_SCRIPT

    # Step 3: Call TTS API
    audio_data = call_telnyx_tts(script_text)
    if audio_data is None:
        print("\n❌ Failed to generate audio. Aborting.")
        sys.exit(1)

    # Step 4: Save raw audio
    raw_file = save_audio_file(audio_data, "demo_raw.wav")
    if raw_file is None:
        print("\n❌ Failed to save raw audio. Aborting.")
        sys.exit(1)

    # Step 5: Post-processing
    normalized_file = OUTPUT_DIR / "demo_normalized.wav"
    trimmed_file = OUTPUT_DIR / "demo_trimmed.wav"
    opus_file = OUTPUT_DIR / "demo.opus"
    mp3_file = OUTPUT_DIR / "demo.mp3"

    # Normalize volume
    if not normalize_audio(raw_file, normalized_file):
        print("\n⚠️  Volume normalization failed, using raw audio")
        normalized_file = raw_file

    # Trim silence
    if not trim_silence(normalized_file, trimmed_file):
        print("\n⚠️  Silence trimming failed, using normalized audio")
        trimmed_file = normalized_file

    # Convert to Opus (primary)
    if not convert_to_opus(trimmed_file, opus_file):
        print("\n❌ Opus conversion failed")

    # Convert to MP3 (fallback)
    if not convert_to_mp3(trimmed_file, mp3_file):
        print("\n❌ MP3 conversion failed")

    # Step 6: Verification
    verify_output_files()

    # Step 7: Next steps
    print_next_steps()

    print("✅ RECORDING COMPLETE\n")


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n\n⚠️  Interrupted by user. Exiting.")
        sys.exit(0)
    except Exception as e:
        print(f"\n❌ Unexpected error: {e}")
        import traceback
        traceback.print_exc()
        sys.exit(1)
