#!/usr/bin/env python3
"""
YouTube Channel Archiver
A cross-platform script to download all videos from a YouTube channel using yt-dlp.
Supports macOS, Linux, and Windows.
"""

import os
import sys
import subprocess
import argparse
import platform
from pathlib import Path

def check_dependencies():
    """Check if yt-dlp is installed and available."""
    try:
        result = subprocess.run(['yt-dlp', '--version'], 
                              capture_output=True, text=True, check=True)
        print(f"[OK] yt-dlp is installed: {result.stdout.strip()}")
        return True
    except (subprocess.CalledProcessError, FileNotFoundError):
        return False

def install_ytdlp():
    """Attempt to install yt-dlp using pip."""
    print("yt-dlp not found. Attempting to install...")
    try:
        subprocess.run([sys.executable, '-m', 'pip', 'install', 'yt-dlp'], 
                      check=True)
        print("[OK] yt-dlp installed successfully!")
        return True
    except subprocess.CalledProcessError:
        print("[ERROR] Failed to install yt-dlp automatically.")
        print("Please install yt-dlp manually:")
        print("  pip install yt-dlp")
        print("  or visit: https://github.com/yt-dlp/yt-dlp")
        return False

def create_download_directory(channel_url, base_path=None):
    """Create a directory for downloads based on channel name."""
    if base_path is None:
        base_path = Path.cwd()
    
    # Extract channel name using yt-dlp
    try:
        result = subprocess.run([
            'yt-dlp', 
            '--print', 'uploader',
            '--playlist-end', '1',  # Only get first video to extract channel name
            channel_url
        ], capture_output=True, text=True, check=True)
        
        channel_name = result.stdout.strip()
        # Clean channel name for use as directory name
        channel_name = "".join(c for c in channel_name if c.isalnum() or c in (' ', '-', '_')).rstrip()
        
    except subprocess.CalledProcessError:
        # Fallback to generic name if channel name extraction fails
        channel_name = "YouTube_Channel_Archive"
    
    download_dir = Path(base_path) / channel_name
    download_dir.mkdir(exist_ok=True)
    
    return download_dir

def download_channel(channel_url, output_dir, quality='best', audio_only=False, 
                    download_thumbnails=True, download_metadata=True):
    """Download all videos from a YouTube channel."""
    
    # Build yt-dlp command
    cmd = ['yt-dlp']
    
    # Output template - organized by upload date
    output_template = str(output_dir / "%(upload_date)s - %(title)s.%(ext)s")
    cmd.extend(['-o', output_template])
    
    # Quality settings
    if audio_only:
        cmd.extend(['-f', 'bestaudio/best'])
    else:
        if quality == 'best':
            cmd.extend(['-f', 'best'])
        elif quality == 'worst':
            cmd.extend(['-f', 'worst'])
        else:
            # Custom quality (e.g., '720p', '1080p')
            cmd.extend(['-f', f'best[height<={quality[:-1]}]'])
    
    # Additional options
    cmd.extend([
        '--ignore-errors',  # Continue on errors
        '--no-overwrites',  # Don't re-download existing files
        '--continue',       # Resume partial downloads
        '--extract-flat',   # Don't download, just list (we'll remove this)
    ])
    
    # Remove extract-flat, we actually want to download
    cmd.remove('--extract-flat')
    
    # Archive file to track downloaded videos
    archive_file = output_dir / 'download_archive.txt'
    cmd.extend(['--download-archive', str(archive_file)])
    
    # Metadata options
    if download_metadata:
        cmd.extend([
            '--write-info-json',    # Save video metadata
            '--write-description',  # Save video description
        ])
    
    # Thumbnail options
    if download_thumbnails:
        cmd.extend([
            '--write-thumbnail',
            '--write-all-thumbnails'  # Get all available thumbnail sizes
        ])
    
    # Add channel URL
    cmd.append(channel_url)
    
    print(f"Starting download to: {output_dir}")
    print(f"Command: {' '.join(cmd)}")
    print("-" * 50)
    
    try:
        # Run the download command
        subprocess.run(cmd, check=True, cwd=output_dir)
        print("-" * 50)
        print("[OK] Download completed successfully!")
        
    except subprocess.CalledProcessError as e:
        print(f"[ERROR] Download failed with error code: {e.returncode}")
        print("Some videos may have been downloaded successfully.")
        return False
    
    except KeyboardInterrupt:
        print("\n[WARNING] Download interrupted by user.")
        print("You can resume later - already downloaded videos won't be re-downloaded.")
        return False
    
    return True

def main():
    parser = argparse.ArgumentParser(
        description="Download all videos from a YouTube channel",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python %(prog)s "https://www.youtube.com/@channelname"
  python %(prog)s "https://www.youtube.com/c/channelname" --quality 720p
  python %(prog)s "https://www.youtube.com/user/username" --audio-only
  python %(prog)s "UCxxxxxxxxxxxxxxxxxxx" --output ./Downloads
        """
    )
    
    parser.add_argument('channel_url', 
                       help='YouTube channel URL or channel ID')
    
    parser.add_argument('--output', '-o', 
                       help='Output directory (default: current directory)')
    
    parser.add_argument('--quality', '-q', 
                       choices=['best', 'worst', '720p', '1080p', '480p'], 
                       default='best',
                       help='Video quality (default: best)')
    
    parser.add_argument('--audio-only', '-a', 
                       action='store_true',
                       help='Download only audio')
    
    parser.add_argument('--no-thumbnails', 
                       action='store_true',
                       help='Skip downloading thumbnails')
    
    parser.add_argument('--no-metadata', 
                       action='store_true',
                       help='Skip downloading metadata files')
    
    args = parser.parse_args()
    
    print(f"YouTube Channel Archiver")
    print(f"Platform: {platform.system()}")
    print("-" * 50)
    
    # Check dependencies
    if not check_dependencies():
        if not install_ytdlp():
            sys.exit(1)
    
    # Create output directory
    try:
        output_dir = create_download_directory(args.channel_url, args.output)
        print(f"Download directory: {output_dir}")
    except Exception as e:
        print(f"[ERROR] Error creating download directory: {e}")
        sys.exit(1)
    
    # Start download
    success = download_channel(
        args.channel_url,
        output_dir,
        quality=args.quality,
        audio_only=args.audio_only,
        download_thumbnails=not args.no_thumbnails,
        download_metadata=not args.no_metadata
    )
    
    if success:
        print(f"\n[OK] All videos downloaded to: {output_dir}")
        print(f"Archive file created at: {output_dir / 'download_archive.txt'}")
    else:
        sys.exit(1)

if __name__ == "__main__":
    main()
