import os
import glob
from flask import Flask, render_template, request, send_file, jsonify, after_this_request
import yt_dlp
import uuid
import mimetypes

import shutil
import imageio_ffmpeg
import threading
import time

app = Flask(__name__)

# Configuración
DOWNLOAD_FOLDER = 'downloads'
if not os.path.exists(DOWNLOAD_FOLDER):
    os.makedirs(DOWNLOAD_FOLDER)

# In-memory storage for tasks
tasks = {}

# Check for ffmpeg
# First check if system ffmpeg is available
SYSTEM_FFMPEG = shutil.which('ffmpeg')
# Then check for imageio-ffmpeg binary
IMAGEIO_FFMPEG = imageio_ffmpeg.get_ffmpeg_exe()

FFMPEG_PATH = SYSTEM_FFMPEG if SYSTEM_FFMPEG else IMAGEIO_FFMPEG
FFMPEG_AVAILABLE = FFMPEG_PATH is not None

@app.route('/')
def index():
    return render_template('index.html', ffmpeg_available=FFMPEG_AVAILABLE)

@app.route('/info', methods=['POST'])
def get_video_info():
    data = request.json
    url = data.get('url')
    
    if not url:
        return jsonify({'error': 'URL requerida'}), 400
        
    try:
        ydl_opts = {
            'quiet': True,
            'no_warnings': True,
        }
        with yt_dlp.YoutubeDL(ydl_opts) as ydl:
            info = ydl.extract_info(url, download=False)
            return jsonify({
                'title': info.get('title'),
                'thumbnail': info.get('thumbnail'),
                'duration': info.get('duration_string')
            })
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/start_download', methods=['POST'])
def start_download():
    data = request.json
    url = data.get('url')
    quality = data.get('quality', 'best')
    task_id = str(uuid.uuid4())
    
    tasks[task_id] = {
        'status': 'starting',
        'progress': 0,
        'message': 'Iniciando...',
        'filename': None,
        'error': None
    }
    
    def download_thread(tid, url, quality):
        try:
            # Generar un nombre de archivo único temporal
            file_uuid = tid
            
            # Definir formato según la calidad seleccionada
            if FFMPEG_AVAILABLE:
                if quality == 'audio':
                    format_str = 'bestaudio/best'
                elif quality == '1080':
                    format_str = 'bestvideo[height<=1080][ext=mp4]+bestaudio[ext=m4a]/best[height<=1080][ext=mp4]/best[ext=mp4]/best'
                elif quality == '720':
                    format_str = 'bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[height<=720][ext=mp4]/best[ext=mp4]/best'
                elif quality == '480':
                    format_str = 'bestvideo[height<=480][ext=mp4]+bestaudio[ext=m4a]/best[height<=480][ext=mp4]/best[ext=mp4]/best'
                else: # best
                    format_str = 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best'
            else:
                if quality == 'audio':
                    format_str = 'bestaudio/best'
                elif quality == '1080':
                    format_str = 'best[height<=1080][ext=mp4]/best[ext=mp4]/best'
                elif quality == '720':
                    format_str = 'best[height<=720][ext=mp4]/best[ext=mp4]/best'
                elif quality == '480':
                    format_str = 'best[height<=480][ext=mp4]/best[ext=mp4]/best'
                else: # best
                    format_str = 'best[ext=mp4]/best'

            def progress_hook(d):
                if d['status'] == 'downloading':
                    try:
                        p = d.get('_percent_str', '0%').replace('%','')
                        tasks[tid]['progress'] = float(p)
                        tasks[tid]['status'] = 'downloading'
                        tasks[tid]['message'] = f"Descargando: {d.get('_percent_str')} - {d.get('_eta_str', '??')} restantes"
                    except:
                        pass
                elif d['status'] == 'finished':
                    tasks[tid]['status'] = 'processing'
                    tasks[tid]['progress'] = 100
                    tasks[tid]['message'] = 'Procesando y convirtiendo...'

            ydl_opts = {
                'format': format_str,
                'outtmpl': os.path.join(DOWNLOAD_FOLDER, f'{file_uuid}.%(ext)s'),
                'quiet': True,
                'no_warnings': True,
                'progress_hooks': [progress_hook],
            }
            
            if FFMPEG_AVAILABLE:
                ydl_opts['ffmpeg_location'] = FFMPEG_PATH

            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                info = ydl.extract_info(url, download=True)
                filename = ydl.prepare_filename(info)
                downloaded_file = filename
                
            if not os.path.exists(downloaded_file):
                 possible_files = glob.glob(os.path.join(DOWNLOAD_FOLDER, f'{file_uuid}.*'))
                 if possible_files:
                     downloaded_file = possible_files[0]
                 else:
                     raise Exception("Archivo no encontrado tras descarga")
            
            tasks[tid]['status'] = 'completed'
            tasks[tid]['message'] = '¡Completado!'
            tasks[tid]['filename'] = downloaded_file
            tasks[tid]['title'] = info.get('title', 'video')
            
        except Exception as e:
            tasks[tid]['status'] = 'error'
            tasks[tid]['error'] = str(e)
            
    thread = threading.Thread(target=download_thread, args=(task_id, url, quality))
    thread.start()
    
    return jsonify({'task_id': task_id})

@app.route('/status/<task_id>')
def get_status(task_id):
    task = tasks.get(task_id)
    if not task:
        return jsonify({'error': 'Task not found'}), 404
    return jsonify(task)

from werkzeug.utils import secure_filename

# ... imports ...

@app.route('/get_file/<task_id>')
def get_file(task_id):
    task = tasks.get(task_id)
    if not task or task['status'] != 'completed':
        return jsonify({'error': 'File not ready'}), 400
        
    downloaded_file = task['filename']
    video_title = task.get('title', 'video')
    
    # Programar eliminación del archivo después de enviarlo
    @after_this_request
    def remove_file(response):
        try:
            if os.path.exists(downloaded_file):
                os.remove(downloaded_file)
            # Clean up task
            if task_id in tasks:
                del tasks[task_id]
        except Exception as e:
            app.logger.error(f"Error cleaning up: {e}")
        return response

    # Obtener extensión original
    _, ext = os.path.splitext(downloaded_file)
    if not ext:
        ext = '.mp4'
        
    # Limpiar nombre de archivo para descarga
    safe_title = secure_filename(video_title)
    if not safe_title:
        safe_title = 'video'
        
    download_name = f"{safe_title}{ext}"
    
    # Adivinar el tipo MIME
    mime_type, _ = mimetypes.guess_type(download_name)
    if not mime_type:
        mime_type = 'application/octet-stream'

    return send_file(
        downloaded_file, 
        as_attachment=True, 
        download_name=download_name,
        mimetype=mime_type
    )

if __name__ == '__main__':
    app.run(debug=True, port=5000)
