import os
import logging
import asyncio
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import Application, CommandHandler, MessageHandler, CallbackQueryHandler, ContextTypes, filters
from all_platforms_fixed_downloader import VideoDownloader

# Enable logging
logging.basicConfig(
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    level=logging.INFO
)
logger = logging.getLogger(__name__)

# Bot token
TOKEN = "7832199348:AAFZqmUwLbMoC_8zVCNQ5otAhsanABwvNbo"

# Compression and download link settings
DEFAULT_TARGET_SIZE_MB = 8  # Target size for video compression
ENABLE_COMPRESSION = True   # Enable compression by default
ENABLE_DOWNLOAD_LINKS = True  # Enable external download links
PUBLIC_PATH = '/var/www/html/downloads'  # Path to public web directory
PUBLIC_URL = 'http://8.215.44.123/downloads'  # Public URL for downloads
LINK_EXPIRY_HOURS = 24  # Hours until download links expire

# Initialize downloader with public path and URL
downloader = VideoDownloader(
    download_path='downloads',
    public_path=PUBLIC_PATH,
    public_url=PUBLIC_URL
)

# Helper function to send files with retry mechanism
async def send_file_with_retry(context, chat_id, file_path, title, is_audio=False, max_retries=3):
    """Helper function to send files with retry mechanism"""
    for attempt in range(max_retries):
        try:
            if is_audio:
                await context.bot.send_audio(
                    chat_id=chat_id,
                    audio=open(file_path, 'rb'),
                    title=title,
                    caption=f"🎵 {title}",
                    read_timeout=60,
                    write_timeout=60
                )
            else:
                await context.bot.send_video(
                    chat_id=chat_id,
                    video=open(file_path, 'rb'),
                    caption=f"🎬 {title}",
                    read_timeout=60,
                    write_timeout=60
                )
            return True
        except Exception as e:
            logger.error(f"Attempt {attempt+1}/{max_retries} failed: {e}")
            if attempt < max_retries - 1:
                await context.bot.send_message(
                    chat_id=chat_id,
                    text=f"⚠️ Pengiriman gagal (percobaan {attempt+1}/{max_retries}). Mencoba lagi..."
                )
                await asyncio.sleep(3)  # Wait before retrying
            else:
                await context.bot.send_message(
                    chat_id=chat_id,
                    text=f"❌ Gagal mengirim file setelah {max_retries} percobaan: {str(e)}\n\n"
                         f"File berhasil diunduh tetapi terjadi masalah saat mengirimkannya."
                )
                return False

# Define command handlers
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Send a message when the command /start is issued."""
    user = update.effective_user
    await update.message.reply_text(
        f"Halo {user.first_name}! 👋\n\n"
        f"Saya adalah bot pengunduh video dari berbagai platform.\n\n"
        f"Kirimkan link video dari YouTube, Facebook, Instagram, TikTok, atau platform lainnya, "
        f"dan saya akan mengunduhkannya untuk Anda.\n\n"
        f"Gunakan /help untuk melihat bantuan lebih lanjut."
    )

async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Send a message when the command /help is issued."""
    await update.message.reply_text(
        "🔍 *Cara Menggunakan Bot Pengunduh Video* 🔍\n\n"
        "1️⃣ Kirim link video dari platform yang didukung:\n"
        "   • YouTube\n"
        "   • Facebook\n"
        "   • Instagram\n"
        "   • TikTok\n"
        "   • Dan platform lainnya\n\n"
        "2️⃣ Pilih format unduhan (video atau audio)\n\n"
        "3️⃣ Tunggu hingga proses unduhan selesai\n\n"
        "4️⃣ Bot akan mengirimkan file video/audio yang telah diunduh\n\n"
        "*Perintah tambahan:*\n"
        "/compress_on - Mengaktifkan kompresi video otomatis\n"
        "/compress_off - Menonaktifkan kompresi video\n"
        "/compress_size [MB] - Mengatur ukuran target kompresi (dalam MB)\n"
        "/link_on - Mengaktifkan link download eksternal\n"
        "/link_off - Menonaktifkan link download eksternal\n"
        "/link_expiry [jam] - Mengatur waktu kedaluwarsa link (dalam jam)\n\n"
        "⚠️ *Catatan:* Ukuran file maksimum yang dapat dikirim melalui Telegram adalah 50MB",
        parse_mode='Markdown'
    )

async def about_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Send a message when the command /about is issued."""
    await update.message.reply_text(
        "🤖 *Bot Pengunduh Video* 🤖\n\n"
        "Bot ini memungkinkan Anda mengunduh video dari berbagai platform seperti "
        "YouTube, Facebook, Instagram, TikTok, dan lainnya.\n\n"
        "Dibuat dengan ❤️ menggunakan:\n"
        "• Python\n"
        "• python-telegram-bot\n"
        "• yt-dlp\n"
        "• pytube\n"
        "• ffmpeg (untuk kompresi video)\n\n"
        "Versi: 3.0.0 (Dengan kompresi video dan link download eksternal)",
        parse_mode='Markdown'
    )

async def compress_on_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Enable video compression"""
    global ENABLE_COMPRESSION
    ENABLE_COMPRESSION = True
    await update.message.reply_text(
        "✅ Kompresi video otomatis telah DIAKTIFKAN.\n\n"
        f"Video akan dikompresi ke ukuran target {DEFAULT_TARGET_SIZE_MB}MB sebelum dikirim."
    )

async def compress_off_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Disable video compression"""
    global ENABLE_COMPRESSION
    ENABLE_COMPRESSION = False
    await update.message.reply_text(
        "⚠️ Kompresi video otomatis telah DINONAKTIFKAN.\n\n"
        "Video akan dikirim tanpa kompresi. Ini mungkin menyebabkan timeout jika ukuran file besar."
    )

async def compress_size_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Set compression target size"""
    global DEFAULT_TARGET_SIZE_MB
    
    if not context.args:
        await update.message.reply_text(
            f"Ukuran target kompresi saat ini adalah {DEFAULT_TARGET_SIZE_MB}MB.\n\n"
            "Untuk mengubah, gunakan format: /compress_size [ukuran dalam MB]\n"
            "Contoh: /compress_size 10"
        )
        return
    
    try:
        size = int(context.args[0])
        if size < 1 or size > 50:
            await update.message.reply_text(
                "❌ Ukuran target harus antara 1MB dan 50MB."
            )
            return
        
        DEFAULT_TARGET_SIZE_MB = size
        await update.message.reply_text(
            f"✅ Ukuran target kompresi diubah menjadi {DEFAULT_TARGET_SIZE_MB}MB."
        )
    except ValueError:
        await update.message.reply_text(
            "❌ Format tidak valid. Gunakan angka bulat untuk ukuran dalam MB.\n"
            "Contoh: /compress_size 10"
        )

async def link_on_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Enable external download links"""
    global ENABLE_DOWNLOAD_LINKS
    ENABLE_DOWNLOAD_LINKS = True
    await update.message.reply_text(
        "✅ Link download eksternal telah DIAKTIFKAN.\n\n"
        "Jika pengiriman file melalui Telegram gagal, bot akan memberikan link download alternatif."
    )

async def link_off_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Disable external download links"""
    global ENABLE_DOWNLOAD_LINKS
    ENABLE_DOWNLOAD_LINKS = False
    await update.message.reply_text(
        "⚠️ Link download eksternal telah DINONAKTIFKAN.\n\n"
        "Bot hanya akan mencoba mengirim file melalui Telegram."
    )

async def link_expiry_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Set download link expiry time"""
    global LINK_EXPIRY_HOURS
    
    if not context.args:
        await update.message.reply_text(
            f"Waktu kedaluwarsa link saat ini adalah {LINK_EXPIRY_HOURS} jam.\n\n"
            "Untuk mengubah, gunakan format: /link_expiry [jam]\n"
            "Contoh: /link_expiry 48"
        )
        return
    
    try:
        hours = int(context.args[0])
        if hours < 1 or hours > 168:  # Max 1 week
            await update.message.reply_text(
                "❌ Waktu kedaluwarsa harus antara 1 dan 168 jam (1 minggu)."
            )
            return
        
        LINK_EXPIRY_HOURS = hours
        await update.message.reply_text(
            f"✅ Waktu kedaluwarsa link diubah menjadi {LINK_EXPIRY_HOURS} jam."
        )
    except ValueError:
        await update.message.reply_text(
            "❌ Format tidak valid. Gunakan angka bulat untuk waktu dalam jam.\n"
            "Contoh: /link_expiry 48"
        )

async def handle_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle URLs sent by the user."""
    url = update.message.text.strip()
    
    # Check if the message contains a valid URL
    if not (url.startswith('http://') or url.startswith('https://')):
        await update.message.reply_text("Mohon kirimkan URL yang valid.")
        return
    
    # Store URL in user data
    context.user_data['url'] = url
    
    # Determine platform
    platform = downloader.get_platform(url)
    platform_name = platform.capitalize()
    
    # Send options to user
    keyboard = [
        [
            InlineKeyboardButton("Video 🎬", callback_data=f"video_{platform}"),
            InlineKeyboardButton("Audio 🎵", callback_data=f"audio_{platform}")
        ]
    ]
    reply_markup = InlineKeyboardMarkup(keyboard)
    
    await update.message.reply_text(
        f"Link {platform_name} terdeteksi! Pilih format yang ingin diunduh:",
        reply_markup=reply_markup
    )

async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
    """Handle button callbacks with improved error handling, compression, and external links."""
    query = update.callback_query
    await query.answer()
    
    # Get callback data
    data = query.data
    url = context.user_data.get('url')
    
    if not url:
        await query.edit_message_text("Sesi telah kedaluwarsa. Silakan kirim URL lagi.")
        return
    
    # Parse callback data
    format_type, platform = data.split('_')
    audio_only = format_type == 'audio'
    
    # Send processing message
    processing_message = await query.edit_message_text(
        f"⏳ Sedang memproses {'audio' if audio_only else 'video'} dari {platform.capitalize()}...\n"
        f"Mohon tunggu sebentar."
    )
    
    try:
        # Send status update
        await context.bot.send_message(
            chat_id=update.effective_chat.id,
            text=f"🔄 Sedang memproses video dari {platform.capitalize()}...\n"
                 f"Proses ini mungkin memerlukan waktu beberapa saat tergantung ukuran video."
        )
        
        # Download the video/audio with compression if enabled
        result = downloader.download(
            url, 
            audio_only=audio_only,
            compress=ENABLE_COMPRESSION and not audio_only,  # Only compress videos, not audio
            target_size_mb=DEFAULT_TARGET_SIZE_MB
        )
        
        if not result['success']:
            error_msg = result['error']
            logger.error(f"Download failed: {error_msg}")
            
            # Provide more helpful error messages based on error type
            if "HTTP Error 400" in error_msg:
                await context.bot.send_message(
                    chat_id=update.effective_chat.id,
                    text=f"❌ Gagal mengunduh: Video tidak dapat diakses.\n\n"
                         f"Kemungkinan penyebab:\n"
                         f"• Video memiliki pembatasan usia atau geografis\n"
                         f"• Video memerlukan login\n"
                         f"• URL tidak valid atau video telah dihapus\n\n"
                         f"Coba video lain atau laporkan masalah ini."
                )
            elif "unavailable" in error_msg.lower() or "not available" in error_msg.lower():
                await context.bot.send_message(
                    chat_id=update.effective_chat.id,
                    text=f"❌ Gagal mengunduh: Video tidak tersedia.\n\n"
                         f"Video ini mungkin:\n"
                         f"• Bersifat pribadi\n"
                         f"• Telah dihapus\n"
                         f"• Tidak tersedia di negara Anda\n\n"
                         f"Silakan coba video lain."
                )
            else:
                await context.bot.send_message(
                    chat_id=update.effective_chat.id,
                    text=f"❌ Gagal mengunduh: {error_msg}\n\n"
                         f"Silakan coba lagi nanti atau coba video lain."
                )
            return
        
        file_path = result['file_path']
        title = result['title']
        format_name = 'MP3' if audio_only else 'Video'
        compressed = result.get('compressed', False)
        
        # Check file size
        file_size = os.path.getsize(file_path) / (1024 * 1024)  # Size in MB
        
        # Send status message
        compression_info = ""
        if compressed:
            compression_info = f"\n💾 Video telah dikompresi untuk pengiriman yang lebih cepat."
        
        await context.bot.send_message(
            chat_id=update.effective_chat.id,
            text=f"✅ {format_name} berhasil diunduh!\n"
                 f"Judul: {title}\n"
                 f"Ukuran: {file_size:.1f}MB{compression_info}\n\n"
                 f"Mengirim file..."
        )
        
        # Try to send via Telegram first
        if file_size <= 50:  # Telegram's file size limit
            success = await send_file_with_retry(
                context, 
                update.effective_chat.id, 
                file_path, 
                title, 
                is_audio=audio_only
            )
            
            # If sending via Telegram fails and external links are enabled, create download link
            if not success and ENABLE_DOWNLOAD_LINKS:
                link_result = downloader.create_public_download_link(
                    file_path, 
                    title, 
                    expiry_hours=LINK_EXPIRY_HOURS
                )
                
                if link_result['success']:
                    await context.bot.send_message(
                        chat_id=update.effective_chat.id,
                        text=f"📥 Pengiriman melalui Telegram gagal, tetapi Anda dapat mengunduh file melalui link berikut:\n\n"
                             f"🔗 [Unduh {title}]({link_result['url']})\n\n"
                             f"⚠️ Link akan kedaluwarsa dalam {LINK_EXPIRY_HOURS} jam.",
                        parse_mode='Markdown',
                        disable_web_page_preview=True
                    )
                else:
                    await context.bot.send_message(
                        chat_id=update.effective_chat.id,
                        text=f"❌ Gagal membuat link download: {link_result.get('error', 'Unknown error')}\n\n"
                             f"Silakan coba lagi nanti."
                    )
        else:
            # File is too large for Telegram, create download link if enabled
            if ENABLE_DOWNLOAD_LINKS:
                await context.bot.send_message(
                    chat_id=update.effective_chat.id,
                    text=f"⚠️ File terlalu besar ({file_size:.1f}MB) untuk dikirim melalui Telegram (batas 50MB).\n\n"
                         f"Membuat link download alternatif..."
                )
                
                link_result = downloader.create_public_download_link(
                    file_path, 
                    title, 
                    expiry_hours=LINK_EXPIRY_HOURS
                )
                
                if link_result['success']:
                    await context.bot.send_message(
                        chat_id=update.effective_chat.id,
                        text=f"📥 Anda dapat mengunduh file melalui link berikut:\n\n"
                             f"🔗 [Unduh {title}]({link_result['url']})\n\n"
                             f"⚠️ Link akan kedaluwarsa dalam {LINK_EXPIRY_HOURS} jam.",
                        parse_mode='Markdown',
                        disable_web_page_preview=True
                    )
                else:
                    await context.bot.send_message(
                        chat_id=update.effective_chat.id,
                        text=f"❌ Gagal membuat link download: {link_result.get('error', 'Unknown error')}\n\n"
                             f"Silakan coba lagi nanti."
                    )
            else:
                await context.bot.send_message(
                    chat_id=update.effective_chat.id,
                    text=f"⚠️ File terlalu besar ({file_size:.1f}MB) untuk dikirim melalui Telegram (batas 50MB).\n\n"
                         f"Aktifkan fitur link download eksternal dengan perintah /link_on untuk mengatasi masalah ini."
                )
        
        # Delete the file to save space (original file, not the one in public directory)
        os.remove(file_path)
        
    except Exception as e:
        logger.error(f"Error in button_callback: {e}")
        await context.bot.send_message(
            chat_id=update.effective_chat.id,
            text=f"❌ Terjadi kesalahan: {str(e)}\n\n"
                 f"Silakan coba lagi nanti. Jika masalah berlanjut, hubungi administrator bot."
        )

def main() -> None:
    """Start the bot."""
    # Create the Application
    application = Application.builder().token(TOKEN).build()

    # Add handlers
    application.add_handler(CommandHandler("start", start))
    application.add_handler(CommandHandler("help", help_command))
    application.add_handler(CommandHandler("about", about_command))
    application.add_handler(CommandHandler("compress_on", compress_on_command))
    application.add_handler(CommandHandler("compress_off", compress_off_command))
    application.add_handler(CommandHandler("compress_size", compress_size_command))
    application.add_handler(CommandHandler("link_on", link_on_command))
    application.add_handler(CommandHandler("link_off", link_off_command))
    application.add_handler(CommandHandler("link_expiry", link_expiry_command))
    application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_url))
    application.add_handler(CallbackQueryHandler(button_callback))

    # Create downloads directory if it doesn't exist
    os.makedirs('downloads', exist_ok=True)
    
    # Create public downloads directory if it doesn't exist
    os.makedirs(PUBLIC_PATH, exist_ok=True)

    # Log startup message
    logger.info("Bot started with video compression and external download links. Press Ctrl+C to stop.")
    
    try:
        # Run the bot until the user presses Ctrl-C
        application.run_polling(allowed_updates=Update.ALL_TYPES)
    except KeyboardInterrupt:
        logger.info("Bot stopped by user.")
    except Exception as e:
        logger.error(f"Error running bot: {e}")
        import sys
        sys.exit(1)

if __name__ == '__main__':
    main()
