import os
import re
import yt_dlp
from pytube import YouTube
import logging

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

class VideoDownloader:
    def __init__(self, download_path='downloads'):
        self.download_path = download_path
        # Ensure download directory exists
        os.makedirs(download_path, exist_ok=True)
    
    def get_platform(self, url):
        """Determine the platform from the URL"""
        if 'youtube.com' in url or 'youtu.be' in url:
            return 'youtube'
        elif 'facebook.com' in url or 'fb.com' in url or 'fb.watch' in url:
            return 'facebook'
        elif 'instagram.com' in url:
            return 'instagram'
        elif 'tiktok.com' in url:
            return 'tiktok'
        else:
            return 'generic'
    
    def download_youtube(self, url, audio_only=False):
        """Download video from YouTube using pytube with improved error handling"""
        try:
            yt = YouTube(url)
            if audio_only:
                # Download audio only
                stream = yt.streams.filter(only_audio=True).first()
                if not stream:
                    logger.error(f"No audio stream found for {url}")
                    return {'success': False, 'error': 'No audio stream found'}
                
                out_file = stream.download(output_path=self.download_path)
                # Convert to mp3
                base, _ = os.path.splitext(out_file)
                mp3_file = base + '.mp3'
                os.rename(out_file, mp3_file)
                return {'success': True, 'file_path': mp3_file, 'title': yt.title, 'format': 'mp3'}
            else:
                # Download video with highest resolution
                stream = yt.streams.get_highest_resolution()
                if not stream:
                    logger.error(f"No video stream found for {url}")
                    return {'success': False, 'error': 'No video stream found'}
                
                out_file = stream.download(output_path=self.download_path)
                return {'success': True, 'file_path': out_file, 'title': yt.title, 'format': 'mp4'}
        except Exception as e:
            logger.error(f"Error downloading from YouTube with pytube: {str(e)}")
            # If pytube fails, try with yt-dlp as fallback
            logger.info(f"Falling back to yt-dlp for {url}")
            return self.download_with_ytdlp(url, audio_only)
    
    def download_with_ytdlp(self, url, audio_only=False):
        """Download video using yt-dlp for all platforms with improved error handling"""
        try:
            platform = self.get_platform(url)
            filename = f"{platform}_{os.urandom(4).hex()}"
            output_template = os.path.join(self.download_path, filename)
            
            # Enhanced yt-dlp options with better error handling
            ydl_opts = {
                'outtmpl': output_template + '.%(ext)s',
                'quiet': False,  # Changed to False to see more info
                'no_warnings': False,  # Changed to False to see warnings
                'verbose': True,  # Added for more detailed logs
                'ignoreerrors': True,  # Skip unavailable videos in a playlist
                'nocheckcertificate': True,  # Ignore SSL cert verification
                'geo_bypass': True,  # Try to bypass geo-restrictions
                'retries': 10,  # Retry 10 times if download fails
                'socket_timeout': 30,  # Timeout after 30 seconds
            }
            
            if audio_only:
                ydl_opts.update({
                    'format': 'bestaudio/best',
                    'postprocessors': [{
                        'key': 'FFmpegExtractAudio',
                        'preferredcodec': 'mp3',
                        'preferredquality': '192',
                    }],
                })
                final_ext = 'mp3'
            else:
                ydl_opts.update({
                    'format': 'best',
                })
                final_ext = 'mp4'  # Most common, but might be different
            
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                logger.info(f"Attempting to download {url} with yt-dlp")
                info = ydl.extract_info(url, download=True)
                
                if not info:
                    logger.error(f"No information extracted for {url}")
                    return {'success': False, 'error': 'Failed to extract video information'}
                
                if 'entries' in info:  # Playlist
                    if not info['entries']:
                        logger.error(f"Empty playlist or all videos failed for {url}")
                        return {'success': False, 'error': 'Empty playlist or all videos failed'}
                    info = info['entries'][0]
                
                # Get the actual file extension
                if not audio_only:
                    final_ext = info.get('ext', 'mp4')
                
                title = info.get('title', 'Video')
                file_path = f"{output_template}.{final_ext}"
                
                # Verify file exists
                if not os.path.exists(file_path):
                    # Try to find the actual file
                    possible_files = [f for f in os.listdir(self.download_path) if f.startswith(filename)]
                    if possible_files:
                        file_path = os.path.join(self.download_path, possible_files[0])
                        logger.info(f"Found alternative file: {file_path}")
                    else:
                        logger.error(f"Downloaded file not found at {file_path}")
                        return {'success': False, 'error': 'Downloaded file not found'}
                
                return {
                    'success': True, 
                    'file_path': file_path, 
                    'title': title, 
                    'format': final_ext
                }
        except Exception as e:
            logger.error(f"Error downloading with yt-dlp: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def download(self, url, audio_only=False):
        """Main download method that routes to appropriate downloader with improved error handling"""
        logger.info(f"Starting download for {url}, audio_only={audio_only}")
        platform = self.get_platform(url)
        logger.info(f"Detected platform: {platform}")
        
        # Try yt-dlp first for all platforms as it's more robust
        result = self.download_with_ytdlp(url, audio_only)
        
        # If yt-dlp fails for YouTube and we're downloading video, try pytube as fallback
        if not result['success'] and platform == 'youtube' and not audio_only:
            logger.info(f"yt-dlp failed, trying pytube for {url}")
            result = self.download_youtube(url, audio_only)
        
        return result
