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

from .ai_video.main_app import main_async
from .helper import *
# Video jobs database module import
from .video_jobs_db import (
    create_job, update_job_progress, complete_job, 
    fail_job, cancel_job, get_job, get_user_jobs
)

from utils.decorators import require_api_key
# TTS service import
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
)

# Multi-voice TTS module import
from .multi_voice_tts import (
    generate_from_script,
    get_available_voices
)

# Image generation ko lagi g4f use garne
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.")

# PDF podcast functionality import
from .ai_podcast.pdf_to_imag import pdf_to_podcast
from .ai_podcast.podcast import PodcastGenerator, PodcastConfig
import tempfile
import uuid

# pdf2image available cha ki nai check garne
try:
    from pdf2image import convert_from_path
    PDF2IMAGE_AVAILABLE = True
except ImportError:
    PDF2IMAGE_AVAILABLE = False
    logging.warning("pdf2image not available. PDF podcast generation will be limited. Install with: pip install pdf2image")

# Audio routes ko Blueprint create garne
audio_bp = Blueprint('audio', __name__, url_prefix='/api/audio_generation')

# Setup logging
logger = logging.getLogger(__name__)

# Generated audio files rakne folder - tts_service.py ma bhako sanga same use garne
AUDIO_DIR = AUDIO_OUTPUT_DIR

# Generated images rakne folder
IMAGE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "generated_media")
VIDEO_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),"podcast_output")


os.makedirs(IMAGE_DIR, exist_ok=True)
os.makedirs(VIDEO_DIR, exist_ok=True)

# Audio directory exist garcha bhanne ensure garne
os.makedirs(AUDIO_DIR, exist_ok=True)

# API key validation decorator


# URL bata image download garera save garne function
def save_generated_image(image_url, prompt_text=None):
    """
    URL bata image download garera local storage ma save garcha
    
    Args:
        image_url: Download garne image ko URL
        prompt_text: Optional text jo image generate garna use bhayeko thiyo
        
    Returns:
        dict: Saved image ko information including filename and local URL
    """
    # Unique filename generate garne
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    # Prompt bata safe filename banaune
    safe_text = ""
    if prompt_text:
        # Prompt text lai safe filename characters ma convert garne
        safe_text = ''.join(c if c.isalnum() else '_' for c in prompt_text[:30])
        safe_text = f"_{safe_text[:20]}"
    
    # Timestamp ra unique ID sanga filename create garne
    unique_id = uuid.uuid4().hex[:8]
    filename = f"{timestamp}{safe_text}_{unique_id}.jpg"
    file_path = os.path.join(IMAGE_DIR, filename)
    
    # Image download garne
    response = requests.get(image_url, stream=True)
    response.raise_for_status()
    
    # Image save garne
    with open(file_path, 'wb') as f:
        for chunk in response.iter_content(8192):
            f.write(chunk)
            
    # Saved image ko information return garne
    return {
        "filename": filename,
        "local_path": file_path,
        "size": os.path.getsize(file_path)
    }

@audio_bp.route('/languages', methods=['GET'])
@require_api_key
def languages():
    """TTS ko lagi available languages haru get garne"""
    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'])
@require_api_key
def voices():
    """TTS voices haru get garne, language filter garna milne"""
    try:
        language = request.args.get('language')
        
        if language:
            # Specific language ko voices return garne
            voices_data = get_voices_for_language(language)
            return jsonify({
                "status": "success",
                "language": language,
                "voices": voices_data
            })
        else:
            # Sabai voices language anusar grouped return garne
            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'])
@require_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'])
@require_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'])
@require_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'])
@require_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'])
# @require_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'])
@require_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'])
# @require_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('/video/<filename>', methods=['GET'])
@require_api_key
def get_video(filename):
    """Serve generated video files with optimized performance"""
    try:
        # Validate filename format for security (more efficient regex check)
        if not filename.lower().endswith('.mp4'):
            return jsonify({
                "status": "error",
                "message": "Invalid video filename format"
            }), 400
        
        # Sanitize filename to prevent path traversal attacks
        filename = os.path.basename(filename)
        
        # Get the file path directly from VIDEO_DIR
        file_path = os.path.join(VIDEO_DIR, filename)
        
        # Check if file exists (single check, no directory listing)
        if not os.path.exists(file_path):
            logger.error(f"Video file not found: {file_path}")
            return jsonify({
                "status": "error",
                "message": "Video file not found"
            }), 404
        
        # Check if it's actually a file (not a directory)
        if not os.path.isfile(file_path):
            logger.error(f"Path exists but is not a file: {file_path}")
            return jsonify({
                "status": "error",
                "message": "Invalid file path"
            }), 404
        
      
  
        response = send_from_directory(
            VIDEO_DIR,
            filename,
            as_attachment=False,
            mimetype='video/mp4'
        )
        
    
        
        return response
        
    except FileNotFoundError:
        logger.error(f"Video file not found: {filename}")
        return jsonify({
            "status": "error",
            "message": "Video file not found"
        }), 404
    except PermissionError:
        logger.error(f"Permission denied accessing video file: {filename}")
        return jsonify({
            "status": "error",
            "message": "Access denied"
        }), 403
    except Exception as e:
        logger.error(f"Error serving video file: {e}")
        return jsonify({
            "status": "error",
            "message": "Internal server error"
        }), 500


# Global job tracking
active_jobs = {}

def cleanup_old_jobs():
    """Clean up completed jobs older than 1 hour and failed jobs older than 30 minutes"""
    now = datetime.now()
    jobs_to_remove = []
    
    for job_id, job in active_jobs.items():
        # Parse timestamps
        created_at = datetime.fromisoformat(job['created_at']) if 'created_at' in job else now
        
        # Remove completed jobs after 1 hour
        if job['status'] == 'completed' and 'completed_at' in job:
            completed_at = datetime.fromisoformat(job['completed_at'])
            if (now - completed_at) > timedelta(hours=1):
                jobs_to_remove.append(job_id)
        
        # Remove failed jobs after 30 minutes
        elif job['status'] == 'failed' and 'failed_at' in job:
            failed_at = datetime.fromisoformat(job['failed_at'])
            if (now - failed_at) > timedelta(minutes=30):
                jobs_to_remove.append(job_id)
        
        # Remove stuck jobs after 2 hours
        elif (now - created_at) > timedelta(hours=2):
            jobs_to_remove.append(job_id)
    
    # Remove jobs from the dictionary
    for job_id in jobs_to_remove:
        # Clean up progress file if it exists
        progress_file = active_jobs[job_id].get('progress_file')
        if progress_file and os.path.exists(progress_file):
            try:
                os.remove(progress_file)
            except:
                pass
        # Remove job from dictionary
        active_jobs.pop(job_id, None)

@audio_bp.route('/generate-video-podcast', methods=['POST'])
@require_api_key
def generate_video_podcast():
    server_url = request.url_root.rstrip('/')

    if not g4f_available:
        return jsonify({
            "status": "error",
            "message": "Video generation is not available. g4f library not installed."
        }), 500
    
    # Clean up old jobs first
    cleanup_old_jobs()
    
    data = request.get_json()
    
    if not data:
        return jsonify({
            "status": "error",
            "message": "Missing request data"
        }), 400
    
    text = data.get('subject', '')
    language = data.get('language', 'English')  # Default language
    user_id = data.get('user_id', 0)  # Get user_id from request if provided
    
    if not text or len(text) < 3:
        return jsonify({
            "status": "error",
            "message": "Subject text is too short or missing"
        }), 400
    
    # Generate a unique job ID
    job_id = str(uuid.uuid4())
    
    # Create progress file path
    progress_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 
                                "tmp", f"progress_{job_id}.json")
    
    # Ensure the directory exists
    os.makedirs(os.path.dirname(progress_file), exist_ok=True)
    
    # Initialize progress file
    try:
        with open(progress_file, 'w') as f:
            json.dump({
                "progress": 0,
                "message": "Initializing job",
                "timestamp": time.time()
            }, f)
    except Exception as e:
        logger.error(f"Error creating progress file: {e}")
        progress_file = None
    
    # Create job status entry in memory
    active_jobs[job_id] = {
        "status": "processing",
        "progress": 0,
        "subject": text,
        "language": language,
        "user_id": user_id,
        "created_at": datetime.now().isoformat(),
        "progress_file": progress_file
    }
    
    # Save job to database if user_id provided
    if user_id > 0:
        create_job(job_id, user_id, text, language)
    
    # Import ProgressCallback from the video_gen module
    from .ai_video.video_gen import ProgressCallback
    
    # Start processing in background thread
    def process_video():
        try:
            # Update progress file
            progress_callback = ProgressCallback(progress_file=progress_file, total_steps=100)
            progress_callback.update(5, "Generating podcast data")
            
            # Update database with progress if user_id provided
            if user_id > 0:
                update_job_progress(job_id, 5, "Generating podcast data")
            
            # Generate podcast data
            context, specific_focus = generate_video_podcast_data(text, language)
            progress_callback.update(10, "Preparing video generation")
            
            # Update database with progress if user_id provided
            if user_id > 0:
                update_job_progress(job_id, 10, "Preparing video generation")
            
            # Generate the video - passing job_id to ensure it's included in file names
            video_path = main_async(text, context, specific_focus, language, progress_callback=progress_callback, job_id=job_id)
            
            # Check if the job was canceled
            if job_id not in active_jobs:
                logger.info(f"Job {job_id} was canceled during processing")
                if user_id > 0:
                    cancel_job(job_id)
                return
            
            # Format the final URL path
            final_video_path = f"{server_url}/api/audio_generation/video/{video_path}"
            
            # Update job status on completion in memory
            active_jobs[job_id].update({
                "status": "completed",
                "video_url": final_video_path,
                "filename": video_path,
                "completed_at": datetime.now().isoformat(),
                "progress": 100
            })
            
            # Update database if user_id provided
            if user_id > 0:
                complete_job(job_id, video_path)
            
            # Clean up temporary files
            try:
                # Clean up progress file
                if progress_file and os.path.exists(progress_file):
                    os.remove(progress_file)
                    logger.info(f"Cleaned up progress file for job {job_id}")
                
                # Clean up temporary image files
                temp_image_dir = os.path.join(VIDEO_DIR, "temp_images")
                if os.path.exists(temp_image_dir):
                    for file in os.listdir(temp_image_dir):
                        # Only remove files related to this job (based on naming convention)
                        if job_id in file or (file.startswith(f"segment_") and file.endswith(".jpg")):
                            try:
                                os.remove(os.path.join(temp_image_dir, file))
                            except Exception as e:
                                logger.warning(f"Could not remove temp image {file}: {e}")
                
                # Clean up temporary audio files
                temp_audio_dir = os.path.join(VIDEO_DIR, "temp_audio")
                if os.path.exists(temp_audio_dir):
                    for file in os.listdir(temp_audio_dir):
                        # Only remove files related to this job (based on naming convention)
                        if job_id in file or (file.startswith(f"segment_") and file.endswith(".wav")):
                            try:
                                os.remove(os.path.join(temp_audio_dir, file))
                            except Exception as e:
                                logger.warning(f"Could not remove temp audio {file}: {e}")
                
                logger.info(f"Completed cleanup for job {job_id}")
            except Exception as cleanup_error:
                logger.warning(f"Error during cleanup for job {job_id}: {cleanup_error}")
            
            logger.info(f"Video generation completed successfully for job {job_id}")
            
        except Exception as e:
            # Check if job still exists
            if job_id not in active_jobs:
                logger.info(f"Job {job_id} was removed during error handling")
                return
                
            logger.error(f"Error in video generation for job {job_id}: {e}")
            
            # Update in-memory job status
            active_jobs[job_id].update({
                "status": "failed",
                "error": str(e),
                "failed_at": datetime.now().isoformat()
            })
            
            # Update database if user_id provided
            if user_id > 0:
                fail_job(job_id, str(e))
    
    # Launch the processing thread
    thread = threading.Thread(target=process_video)
    thread.daemon = True
    thread.start()
    
    # Return immediately with job ID
    return jsonify({
        "status": "accepted",
        "message": "Video generation started",
        "job_id": job_id
    })

@audio_bp.route('/job-status/<job_id>', methods=['GET'])
@require_api_key
def job_status(job_id):
    """Check status of video generation job"""
    # First check active jobs in memory
    if job_id in active_jobs:
        job = active_jobs[job_id]
        
        # Check progress file for latest status
        progress_file = job.get('progress_file')
        if progress_file and os.path.exists(progress_file):
            try:
                with open(progress_file, 'r') as f:
                    progress_data = json.load(f)
                    # Update job with latest progress
                    job['progress'] = progress_data.get('progress', job.get('progress', 0))
                    job['progress_message'] = progress_data.get('message', '')
                    job['last_update'] = progress_data.get('timestamp', time.time())
            except Exception as e:
                logger.error(f"Error reading progress file for job {job_id}: {e}")
        
        # If job completed, return the video URL
        if job["status"] == "completed":
            return jsonify({
                "status": "success",
                "job_status": job["status"],
                "subject": job["subject"],
                "video_url": job["video_url"],
                "filename": job["filename"],
                "progress": 100,
                "message": job.get('progress_message', 'Video generation complete')
            })
        # If job failed, return the error
        elif job["status"] == "failed":
            return jsonify({
                "status": "error",
                "job_status": job["status"],
                "message": job.get("error", "Unknown error during processing"),
                "progress": job.get("progress", 0),
                "progress_message": job.get('progress_message', '')
            })
        # If job still processing, return progress
        else:
            return jsonify({
                "status": "pending",
                "job_status": job["status"],
                "message": "Video still being generated, please check again later",
                "progress": job.get("progress", 0),
                "progress_message": job.get('progress_message', '')
            })
    else:
        # If not in memory, check database
        job = get_job(job_id)
        
        if job:
            # Convert SQLite Row to dictionary properly
            job_dict = {}
            try:
                # For SQLite Row objects
                if hasattr(job, 'keys'):
                    job_dict = {key: job[key] for key in job.keys()}
                # For other dict-like objects
                elif isinstance(job, dict):
                    job_dict = job
                # For tuple-like objects (fallback)
                elif hasattr(job, '__getitem__') and hasattr(job, '__iter__'):
                    # Get column names from database connection
                    import sqlite3
                    if isinstance(job, sqlite3.Row):
                        job_dict = {key: job[key] for key in job.keys()}
                    else:
                        # Just convert to dict as best we can
                        job_dict = dict(job)
                else:
                    # Last resort - try direct attribute access
                    job_dict = {attr: getattr(job, attr) for attr in dir(job) 
                                if not attr.startswith('_') and not callable(getattr(job, attr))}
            except Exception as e:
                logger.error(f"Error converting job to dictionary: {e}")
                # Fallback to empty dict
                job_dict = {}
            
            if job_dict.get('status') == 'completed':
                # Construct video URL
                server_url = request.url_root.rstrip('/')
                video_path = job_dict.get('video_path', '')
                video_url = f"{server_url}/api/audio_generation/video/{video_path}"
                
                return jsonify({
                    "status": "success",
                    "job_status": job_dict.get("status"),
                    "subject": job_dict.get("subject", ""),
                    "video_url": video_url,
                    "filename": video_path,
                    "progress": 100,
                    "message": 'Video generation complete'
                })
            elif job_dict.get('status') == 'failed':
                return jsonify({
                    "status": "error",
                    "job_status": job_dict.get("status"),
                    "message": job_dict.get("error_message", "Unknown error during processing"),
                    "progress": job_dict.get("progress", 0)
                })
            else:
                return jsonify({
                    "status": "pending",
                    "job_status": job_dict.get("status"),
                    "message": "Video still being generated, please check again later",
                    "progress": job_dict.get("progress", 0)
                })
        else:
            return jsonify({
                "status": "error",
                "message": "Job not found or expired"
            }), 404

@audio_bp.route('/user-videos', methods=['GET'])
@require_api_key
def user_videos():
    """Get all video generation jobs for a user"""
    user_id = request.args.get('user_id')
    status = request.args.get('status')
    
    if not user_id:
        return jsonify({
            "status": "error",
            "message": "Missing required parameter: user_id"
        }), 400
    
    try:
        user_id = int(user_id)
    except ValueError:
        return jsonify({
            "status": "error",
            "message": "Invalid user_id format. Must be an integer."
        }), 400
    
    # Get jobs from database
    db_jobs = get_user_jobs(user_id, status)
    
    # If no jobs found
    if not db_jobs:
        return jsonify({
            "status": "success",
            "count": 0,
            "jobs": []
        })
    
    # Convert SQLite rows to proper dictionaries
    jobs = []
    for db_job in db_jobs:
        # Define a helper function to safely convert a db row to dict
        def row_to_dict(row):
            try:
                # For SQLite Row objects
                if hasattr(row, 'keys'):
                    return {key: row[key] for key in row.keys()}
                # For other dict-like objects
                elif isinstance(row, dict):
                    return row
                # For tuple-like objects
                elif hasattr(row, '_asdict'):  # namedtuple support
                    return row._asdict()
                # Last resort - convert to dict
                else:
                    return dict(row)
            except Exception as e:
                logger.error(f"Error converting row to dict: {e}")
                # Return empty dict if conversion fails
                return {}
                
        # Convert the row to a dictionary
        job = row_to_dict(db_job)
        
        # Add to jobs list
        jobs.append(job)
    
    # Add video URLs for completed jobs
    server_url = request.url_root.rstrip('/')
    for job in jobs:
        if job.get('status') == 'completed' and job.get('video_path'):
            job['video_url'] = f"{server_url}/api/audio_generation/video/{job.get('video_path')}"
        
        # Add formatted dates
        for date_field in ['created_at', 'updated_at', 'completed_at']:
            date_value = job.get(date_field)
            if date_value:
                try:
                    # Format date for better readability if it's a string
                    if isinstance(date_value, str):
                        # Handle Z suffix in ISO format
                        if date_value.endswith('Z'):
                            date_value = date_value.replace('Z', '+00:00')
                        # Format the date
                        job[f'{date_field}_formatted'] = datetime.fromisoformat(date_value).strftime('%Y-%m-%d %H:%M:%S')
                except (ValueError, TypeError) as e:
                    logger.warning(f"Could not format date: {e}")
    
    return jsonify({
        "status": "success",
        "count": len(jobs),
        "jobs": jobs
    })


@audio_bp.route('/generate-image', methods=['POST'])
@require_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,
        # model="flux",
        # prompt="a white siamese cat",
        response_format="url"
        
    )
    
            
            # 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'])
@require_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'])
@require_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

@audio_bp.route('/pdf_podcast/generate', methods=['POST'])
@require_api_key
def generate_pdf_podcast():
    """Convert a PDF file to a podcast with AI-generated conversation based on content"""
    try:
        # Check if PDF file is in the request
        if 'pdf_file' not in request.files:
            return jsonify({
                "status": "error",
                "message": "No PDF file provided"
            }), 400
            
        pdf_file = request.files['pdf_file']
        
        # Validate file
        if pdf_file.filename == '':
            return jsonify({
                "status": "error",
                "message": "No file selected"
            }), 400
            
        if not pdf_file.filename or not pdf_file.filename.lower().endswith('.pdf'):
            return jsonify({
                "status": "error",
                "message": "File must be a PDF"
            }), 400
            
        # Get optional title
        title = request.form.get('title', None) or os.path.splitext(pdf_file.filename)[0]
        
        # Get optional podcast style/tone
        tone = request.form.get('tone', 'educational')  # Default to educational tone
        
        # Create a temporary file to save the uploaded PDF
        pdf_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "uploaded_pdfs")
        temp_file_path = os.path.join(pdf_path, f"{uuid.uuid4()}.pdf")
        
        # Save uploaded file
        pdf_file.save(temp_file_path)
        logger.info(f"Saved uploaded PDF to {temp_file_path}")
        
        # Process the PDF and generate podcast
        output_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "generated_audio")
        
        # Generate the podcast with dynamic content generation
        try:
            logger.info(f"Starting PDF podcast generation. PDF2IMAGE_AVAILABLE: {PDF2IMAGE_AVAILABLE}")
            
            # First try with pdf2image if available
            if PDF2IMAGE_AVAILABLE:
                # Use our enhanced pdf_to_podcast function that leverages generate_script.py
                # for dynamic content generation based on the PDF content
                logger.info("Using enhanced PDF processing with image extraction")
                podcast_metadata = pdf_to_podcast(
                    pdf_path=temp_file_path,
                    title=title,
                    output_dir=output_dir
                )
                
                # Log success with dynamic content
                logger.info(f"Generated dynamic podcast from PDF with {len(podcast_metadata.get('images', []))} images")
            else:
                # If pdf2image is not available, create a simple podcast without images
                # This is a fallback method
                from .ai_podcast.podcast import PodcastGenerator, PodcastConfig
                
                logger.warning("pdf2image not available, falling back to simple podcast generation without images")
                
                config = PodcastConfig(output_dir=output_dir)
                podcast_generator = PodcastGenerator(config)
                
                # Create a simple podcast structure
                podcast_data = {
                    "title": f"Audio Guide: {title}",
                    "voice_assignments": {
                        "HOST": "nova",
                        "EXPERT": "onyx"
                    },
                    "segments": [
                        {
                            "speaker": "HOST",
                            "text": f"Welcome to this audio guide about {title}. I'll be walking you through the key points from this document."
                        },
                        {
                            "speaker": "EXPERT",
                            "text": f"This audio guide is generated from a PDF document titled {title}. While we couldn't process the images from the document, I'll provide a general overview of what such documents typically contain."
                        },
                        {
                            "speaker": "HOST",
                            "text": "Please note that this is a simplified audio version. For the full visual content, please refer to the original PDF document."
                        },
                        {
                            "speaker": "EXPERT",
                            "text": "Let me summarize what this kind of document typically covers, based on its title and context."
                        }
                    ]
                }
                
                podcast_json = json.dumps(podcast_data)
                audio_path, podcast_metadata = podcast_generator.generate_podcast_from_json(podcast_json)
                
                # Add necessary metadata
                podcast_metadata['images'] = []
                # Create full URL path for the audio file
                podcast_metadata['audio_url'] = f"/api/audio_generation/audio/{os.path.basename(audio_path)}"
            
            # Add API key to audio URL if needed
            if 'audio_url' in podcast_metadata:
                # Ensure URL has correct scheme and API key
                audio_url = podcast_metadata['audio_url']
                if not audio_url.startswith('/'):
                    audio_url = f"/{audio_url}"
                    
                podcast_metadata['audio_url'] = audio_url
            
            # Add generation timestamp
            podcast_metadata['generated_at'] = datetime.now().isoformat()
            
            # Add tone/style information if available
            if tone:
                podcast_metadata['tone'] = tone
                
            # Return success response with podcast metadata
            return jsonify({
                "status": "success",
                "message": "PDF successfully converted to podcast with dynamic content",
                "image_processing": PDF2IMAGE_AVAILABLE,
                "dynamic_content": PDF2IMAGE_AVAILABLE,  # True if we used the dynamic content generation
                **podcast_metadata
            })
        except Exception as process_error:
            logger.error(f"Error processing PDF: {process_error}")
            return jsonify({
                "status": "error",
                "message": f"Error processing PDF: {str(process_error)}"
            }), 500
        
    except Exception as e:
        logger.error(f"Error generating PDF podcast: {e}")
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500
    finally:
        # Clean up temporary files
        pass
        # try:
        #     if 'temp_file_path' in locals() and os.path.exists(temp_file_path):
        #         os.remove(temp_file_path)
        #     if 'temp_dir' in locals() and os.path.exists(temp_dir):
        #         os.rmdir(temp_dir)
        # except Exception as cleanup_error:
        #     logger.warning(f"Error cleaning up temporary files: {cleanup_error}")