

from flask import Blueprint, request, jsonify, send_from_directory, Response
import os
import json
import logging
import uuid
import requests
from datetime import datetime
from functools import wraps
from ttsfm import AudioFormat

# Import the TTS service
from .tts_service import (
    generate_audio, 
    get_available_languages, 
    get_all_voices, 
    get_voices_for_language, 
    get_audio_file_path,
    cleanup_old_audio_files,
    AUDIO_OUTPUT_DIR
)

# Import the multi-voice TTS module
from .multi_voice_tts import (
    generate_from_script,
    get_available_voices
)

# Import g4f for image generation
try:
    from g4f.client import Client as G4FClient
    g4f_available = True
except ImportError:
    g4f_available = False
    logging.warning("g4f library not available. Image generation will be disabled.")

# Create a Blueprint for audio routes
audio_bp = Blueprint('audio', __name__, url_prefix='/api/audio_generation')

# Setup logging
logger = logging.getLogger(__name__)

# Directory where generated audio files are stored - use the same as in tts_service.py
AUDIO_DIR = AUDIO_OUTPUT_DIR

# Directory for storing generated images
IMAGE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "generated_media")
os.makedirs(IMAGE_DIR, exist_ok=True)

# Ensure the audio directory exists
os.makedirs(AUDIO_DIR, exist_ok=True)

# API key validation decorator
def validate_api_key(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # Get API key from headers, query params, or form data
        api_key = request.headers.get('api_key') or request.args.get('api_key') or request.form.get('api_key')
        
        # Check if API key is valid (simplified for demo)
        # In a real app, check against your actual API key validation logic
        try:
            from config import ALLOWED_KEYS  # Import from your config
        except ImportError:
            # Fallback for development/testing
            ALLOWED_KEYS = ['test_key', 'demo_key']
        
        if api_key not in ALLOWED_KEYS:
            return jsonify({"status": "error", "message": "Invalid API key"}), 401
            
        return f(*args, **kwargs)
    return decorated_function

# Function to save an image from URL
def save_generated_image(image_url, prompt_text=None):
    """
    Downloads and saves an image from URL to local storage
    
    Args:
        image_url: The URL of the image to download
        prompt_text: Optional text used to generate the image
        
    Returns:
        dict: Information about the saved image including filename and local URL
    """
    try:
        # Generate a unique filename
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        # Create a safe filename from the first few chars of the prompt
        safe_text = ""
        if prompt_text:
            # Convert prompt text to safe filename characters
            safe_text = ''.join(c if c.isalnum() else '_' for c in prompt_text[:30])
            safe_text = f"_{safe_text[:20]}"
        
        # Create unique filename with timestamp and unique ID
        unique_id = uuid.uuid4().hex[:8]
        filename = f"{timestamp}{safe_text}_{unique_id}.jpg"
        file_path = os.path.join(IMAGE_DIR, filename)
        
        # Download the image
        response = requests.get(image_url, stream=True)
        response.raise_for_status()
        
        # Save the image
        with open(file_path, 'wb') as f:
            for chunk in response.iter_content(8192):
                f.write(chunk)
                
        # Return information about the saved image
        return {
            "filename": filename,
            "local_path": file_path,
            "size": os.path.getsize(file_path)
        }
        
    except Exception as e:
        logger.error(f"Failed to save image: {e}")
        raise

@audio_bp.route('/languages', methods=['GET'])
@validate_api_key
def languages():
    """Get all available languages for TTS"""
    try:
        languages = get_available_languages()
        return jsonify({
            "status": "success",
            "languages": languages
        })
    except Exception as e:
        logger.error(f"Error getting languages: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/voices', methods=['GET'])
@validate_api_key
def voices():
    """Get all available voices, optionally filtered by language"""
    try:
        language = request.args.get('language')
        
        if language:
            # Return voices for specific language
            voices_data = get_voices_for_language(language)
            return jsonify({
                "status": "success",
                "language": language,
                "voices": voices_data
            })
        else:
            # Return all voices grouped by language
            voices_data = get_all_voices()
            return jsonify({
                "status": "success",
                "voices": voices_data
            })
    except Exception as e:
        logger.error(f"Error getting voices: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/generate', methods=['POST'])
@validate_api_key
def generate_tts():
    """Generate audio from text"""
    try:
        # Get request data
        data = request.get_json()
        
        if not data or 'text' not in data:
            return jsonify({
                "status": "error",
                "message": "Missing required parameter: text"
            }), 400
            
        # Get parameters with defaults
        text = data.get('text', '')
        language_code = data.get('language', 'en-US')
        voice_id = data.get('voice', 'nova')
        speed = float(data.get('speed', 1.0))
        summarize = data.get('summarize', True)  # Default to TRUE for teacher-like summarization
        
        # Validate parameters
        if not text:
            return jsonify({
                "status": "error",
                "message": "Text cannot be empty"
            }), 400
            
        if speed < 0.5 or speed > 2.0:
            return jsonify({
                "status": "error",
                "message": "Speed must be between 0.5 and 2.0"
            }), 400
            
        # Generate audio with teacher-like summarization if requested
        result = generate_audio(
            text=text,
            language_code=language_code,
            voice_id=voice_id,
            format=AudioFormat.MP3,
            speed=speed,
            summarize=summarize  # Pass the summarize parameter
        )
        
        # Return the result
        if result.get('status') == 'success':
            return jsonify(result)
        else:
            return jsonify(result), 500
            
    except Exception as e:
        logger.error(f"Error generating audio: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/generate-teacher', methods=['POST'])
@validate_api_key
def generate_teacher_tts():
    """Generate teacher-style audio from text with AI summarization"""
    try:
        # Get request data
        data = request.get_json()
        
        if not data or 'text' not in data:
            return jsonify({
                "status": "error",
                "message": "Missing required parameter: text"
            }), 400
            
        # Get parameters with defaults
        text = data.get('text', '')
        language_code = data.get('language', 'en-US')
        voice_id = data.get('voice', 'sage')  # Default to sage voice for teacher style
        speed = float(data.get('speed', 1.0))
        
        # Validate parameters
        if not text:
            return jsonify({
                "status": "error",
                "message": "Text cannot be empty"
            }), 400
            
        if speed < 0.5 or speed > 2.0:
            return jsonify({
                "status": "error",
                "message": "Speed must be between 0.5 and 2.0"
            }), 400
            
        # Log the request
        logger.info(f"Generating teacher-style audio for {len(text)} characters of text in {language_code}")
        
        # Generate audio with teacher-like summarization (always TRUE for this endpoint)
        result = generate_audio(
            text=text,
            language_code=language_code,
            voice_id=voice_id,
            format=AudioFormat.MP3,
            speed=speed,
            summarize=True  # Always use summarization for teacher mode
        )
        
        # Return the result
        if result.get('status') == 'success':
            result['teacher_mode'] = True
            return jsonify(result)
        else:
            return jsonify(result), 500
            
    except Exception as e:
        logger.error(f"Error generating teacher audio: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/multi-voice/generate', methods=['POST'])
@validate_api_key
def generate_multi_voice_tts():
    """Generate multi-voice audio from a script with markers"""
    try:
        # Get request data
        data = request.get_json()
        
        if not data or 'script' not in data:
            return jsonify({
                "status": "error",
                "message": "Missing required parameter: script"
            }), 400
        
        # Get parameters
        script_text = data.get('script', '')
        voice_assignments = data.get('voice_assignments', {})
        audio_format = data.get('format', 'mp3').lower()
        language_code = data.get('language', 'en-US')  # Get language code from request
        
        # Validate script
        if not script_text or len(script_text) < 10:
            return jsonify({
                "status": "error",
                "message": "Script is too short or empty"
            }), 400
            
        # Validate audio format
        if audio_format not in ['mp3', 'wav', 'opus']:
            return jsonify({
                "status": "error", 
                "message": "Unsupported audio format. Use mp3, wav, or opus."
            }), 400
        
        # Get API key for TTS service from request headers
        api_key = request.headers.get('api_key') or request.args.get('api_key')
        
        # Log the language being used
        logger.info(f"Generating multi-voice audio in language: {language_code}")
        
        # Generate audio from script
        result = generate_from_script(
            script_text=script_text,
            voice_assignments=voice_assignments,
            api_key=api_key,
            audio_format=audio_format,
            language=language_code  # Pass the language parameter
        )
        
        # Return the result
        if result.get('status') == 'success':
            return jsonify(result)
        else:
            return jsonify(result), 500
            
    except Exception as e:
        logger.error(f"Error generating multi-voice audio: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/multi-voice/voices', methods=['GET'])
@validate_api_key
def multi_voice_voices():
    """Get available voices for multi-voice TTS"""
    try:
        voices_data = get_available_voices()
        return jsonify({
            "status": "success",
            "voices": voices_data
        })
    except Exception as e:
        logger.error(f"Error getting multi-voice voices: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/audio/<filename>', methods=['GET'])
@validate_api_key
def get_audio(filename):
    """Serve generated audio files"""
    try:
        # Validate filename format for security
        if not filename.startswith(('tts_', 'multi_voice_')) or not filename.endswith(('.mp3', '.wav', '.opus')):
            return jsonify({
                "status": "error",
                "message": "Invalid filename format"
            }), 400
            
        # Get the file path
        file_path = get_audio_file_path(filename)
        
        # Check if file exists
        if not os.path.exists(file_path):
            # Log the error and directory contents for debugging
            logger.error(f"Audio file not found: {file_path}")
            logger.info(f"Audio directory contents: {os.listdir(AUDIO_DIR)}")
            
            # Try to find a file with a similar name (for part files)
            base_filename = filename.split('.')[0]
            for f in os.listdir(AUDIO_DIR):
                if f.startswith(base_filename):
                    logger.info(f"Found alternative file: {f}")
                    filename = f
                    file_path = os.path.join(AUDIO_DIR, f)
                    break
            
            # If still not found after trying alternatives
            if not os.path.exists(file_path):
                return jsonify({
                    "status": "error",
                    "message": "Audio file not found"
                }), 404
            
        # Determine MIME type
        mime_type = 'audio/mpeg'
        if filename.endswith('.wav'):
            mime_type = 'audio/wav'
        elif filename.endswith('.opus'):
            mime_type = 'audio/opus'
            
        # Serve the file
        return send_from_directory(
            AUDIO_DIR, 
            filename, 
            as_attachment=False,
            mimetype=mime_type
        )
        
    except Exception as e:
        logger.error(f"Error serving audio file: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500
        
@audio_bp.route('/cleanup', methods=['POST'])
@validate_api_key
def cleanup():
    """Clean up old audio files"""
    try:
        hours = int(request.args.get('hours', 24))
        result = cleanup_old_audio_files(max_age_hours=hours)
        return jsonify({
            "status": "success",
            **result
        })
    except Exception as e:
        logger.error(f"Error during cleanup: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500 

@audio_bp.route('/image/<filename>', methods=['GET'])
@validate_api_key
def get_image(filename):
    """Serve generated Image files"""
    try:
        # Validate filename format for security
        # For images, we'll check for common image extensions
        if not filename.endswith(('.jpg', '.jpeg', '.png', '.webp')):
            return jsonify({
                "status": "error",
                "message": "Invalid image filename format"
            }), 400
            
        # Get the file path directly from IMAGE_DIR
        file_path = os.path.join(IMAGE_DIR, filename)
        
        # Check if file exists
        if not os.path.exists(file_path):
            # Log the error and directory contents for debugging
            logger.error(f"Image file not found: {file_path}")
            logger.info(f"Image directory contents: {os.listdir(IMAGE_DIR)}")
            
            # Try to find a file with a similar name
            base_filename = filename.split('.')[0]
            for f in os.listdir(IMAGE_DIR):
                if f.startswith(base_filename):
                    logger.info(f"Found alternative file: {f}")
                    filename = f
                    file_path = os.path.join(IMAGE_DIR, f)
                    break
            
            # If still not found after trying alternatives
            if not os.path.exists(file_path):
                return jsonify({
                    "status": "error",
                    "message": "Image file not found"
                }), 404
            
        # Determine MIME type
        mime_type = 'image/jpeg'
        if filename.endswith('.png'):
            mime_type = 'image/png'
        elif filename.endswith('.webp'):
            mime_type = 'image/webp'
            
        # Serve the file
        return send_from_directory(
            IMAGE_DIR, 
            filename, 
            as_attachment=False,
            mimetype=mime_type
        )
        
    except Exception as e:
        logger.error(f"Error serving image file: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/generate-image', methods=['POST'])
@validate_api_key
def generate_image():
    """Generate an image based on AI response text"""
    if not g4f_available:
        return jsonify({
            "status": "error",
            "message": "Image generation is not available. g4f library not installed."
        }), 500
      #est data
    data = request.get_json()
        
    if not data or 'text' not in data:
        return jsonify({
            "status": "error",
            "message": "Missing required parameter: text"
        }), 400
            
        # Get the AI response text to generate an image from
    text = data.get('text', '')
    model = data.get('model', 'flux')  # Default model
        
    if not text or len(text) < 10:
        return jsonify({
            "status": "error",
            "message": "Text is too short for image generation"
        }), 400
         
        # Initialize g4f client
    g4f_client = G4FClient()
        
        # Generate the image
        
    response = g4f_client.images.generate(
        model=model,
        prompt=text
    )
            
            # Get the image URL from g4f
    external_image_url = response.data[0].url
            
            # Save the image locally
    image_data = save_generated_image(external_image_url, text)
            
            # Build the URL to access this image via our API
    server_url = request.url_root.rstrip('/')
    print(server_url)

            # Create image URL similar to how audio URLs are created
    image_url = f"{server_url}/api/audio_generation/image/{image_data['filename']}"
            
        
            # Return the result
    return jsonify({
        "status": "success",
        "message": "Image generated successfully",
        "image_url": image_url,
        "external_url": external_image_url,
        "filename": image_data['filename'],
        "size_bytes": image_data['size']
    })
            
     
            
 

@audio_bp.route('/cleanup-images', methods=['POST'])
@validate_api_key
def cleanup_images():
    """Clean up old image files"""
    try:
        hours = int(request.args.get('hours', 24))
        max_age = datetime.now().timestamp() - (hours * 3600)
        
        deleted_count = 0
        kept_count = 0
        total_size = 0
        
        for filename in os.listdir(IMAGE_DIR):
            file_path = os.path.join(IMAGE_DIR, filename)
            
            # Skip if not a file
            if not os.path.isfile(file_path):
                continue
                
            # Check file age
            file_time = os.path.getmtime(file_path)
            if file_time < max_age:
                # Delete old file
                file_size = os.path.getsize(file_path)
                os.remove(file_path)
                deleted_count += 1
                total_size += file_size
            else:
                kept_count += 1
                
        return jsonify({
            "status": "success",
            "deleted_files": deleted_count,
            "kept_files": kept_count,
            "freed_space_bytes": total_size
        })
        
    except Exception as e:
        logger.error(f"Error during image cleanup: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@audio_bp.route('/summarize-teacher', methods=['POST'])
@validate_api_key
def summarize_teacher():
    """Generate teacher-style summarization without audio conversion"""
    try:
        import asyncio
        from .tts_service import generate_teacher_summary
        
        # Get request data
        data = request.get_json()
        
        if not data or 'text' not in data:
            return jsonify({
                "status": "error",
                "message": "Missing required parameter: text"
            }), 400
            
        # Get parameters
        text = data.get('text', '')
        language_code = data.get('language', 'en-US')
        
        # Validate parameters
        if not text:
            return jsonify({
                "status": "error",
                "message": "Text cannot be empty"
            }), 400
            
        # Log the request
        logger.info(f"Generating teacher-style summary for {len(text)} characters of text in {language_code}")
        
        # Create and run the event loop for the async call
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        
        # Generate summary
        summary = loop.run_until_complete(generate_teacher_summary(text, language_code))
        loop.close()
        
        # Return the summary
        return jsonify({
            "status": "success",
            "original_length": len(text),
            "summary_length": len(summary),
            "summary": summary
        })
            
    except Exception as e:
        logger.error(f"Error generating teacher summary: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500 