"""
🐺 WolfYouTube Core - Vəhşi YouTube Downloader
"""

import os
import time
import shutil
from pathlib import Path
from typing import Optional, Dict, Any, Callable, List
from concurrent.futures import ThreadPoolExecutor

try:
    import yt_dlp
except ImportError:
    raise ImportError("yt-dlp lazımdır: pip install yt-dlp")

from .exceptions import (
    WolfError, DownloadError, ExtractError,
    GeoBlockedError, AgeRestrictedError, PrivateVideoError,
    VideoUnavailableError
)
from .utils import clean_filename, is_valid_url, SUPPORTED_DOMAINS


class YouTube:
    """
    🐺 WolfYouTube - Vəhşi kimi işləyir, problem yaratmır!

    Example:
        >>> from wolfyoutube import YouTube
        >>> wolf = YouTube()
        >>> result = wolf.download_video("https://youtube.com/watch?v=xxx", "/tmp")
        >>> if result['success']:
        ...     print(f"Downloaded: {result['path']}")
    """

    # Keyfiyyət preset-ləri
    QUALITY_PRESETS = {
        'ultra': {
            'format': 'bestvideo[ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/bestvideo[ext=mp4]+bestaudio/best[ext=mp4]/best',
            'height': None
        },
        'high': {
            'format': 'bestvideo[height<=1080][ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/bestvideo[height<=1080][ext=mp4]+bestaudio/best[height<=1080]/best',
            'height': 1080
        },
        'medium': {
            'format': 'bestvideo[height<=720][ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/bestvideo[height<=720][ext=mp4]+bestaudio/best[height<=720]/best',
            'height': 720
        },
        'low': {
            'format': 'bestvideo[height<=480][ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/bestvideo[height<=480][ext=mp4]+bestaudio/best[height<=480]/best',
            'height': 480
        },
        'lowest': {
            'format': 'bestvideo[height<=360][ext=mp4]+bestaudio/best[height<=360]/worst',
            'height': 360
        }
    }

    # Audio keyfiyyət preset-ləri
    AUDIO_QUALITY = {
        'high': '320',
        'medium': '192',
        'low': '128'
    }

    def __init__(
            self,
            cookies_file: Optional[str] = None,
            proxy: Optional[str] = None,
            max_retries: int = 3,
            retry_delay: int = 2,
            timeout: int = 60,
            quiet: bool = True
    ):
        """
        🐺 Wolf YouTube Downloader

        Args:
            cookies_file: YouTube cookies fayl yolu (age-restricted üçün)
            proxy: Proxy URL (məs: socks5://127.0.0.1:9050)
            max_retries: Maksimum cəhd sayı
            retry_delay: Cəhdlər arası gözləmə (saniyə)
            timeout: Bağlantı timeout-u
            quiet: Səssiz rejim
        """
        self.cookies_file = cookies_file
        self.proxy = proxy
        self.max_retries = max_retries
        self.retry_delay = retry_delay
        self.timeout = timeout
        self.quiet = quiet

        self._ffmpeg_available = self._check_ffmpeg()

    def _check_ffmpeg(self) -> bool:
        """FFmpeg mövcudluğunu yoxla"""
        return shutil.which('ffmpeg') is not None

    @property
    def has_ffmpeg(self) -> bool:
        """FFmpeg mövcuddurmu?"""
        return self._ffmpeg_available

    def _get_base_opts(self) -> Dict:
        """Əsas yt-dlp seçimləri"""
        opts = {
            'quiet': self.quiet,
            'no_warnings': self.quiet,
            'noplaylist': True,
            'geo_bypass': True,
            'socket_timeout': self.timeout,
            'retries': self.max_retries,
            'fragment_retries': self.max_retries,
            'file_access_retries': self.max_retries,
            'extractor_retries': self.max_retries,
            'concurrent_fragment_downloads': 4,
            'buffersize': 1024 * 16,
            'http_chunk_size': 10485760,
            'ignoreerrors': False,
            'nocheckcertificate': True,
            'restrictfilenames': True,
            'windowsfilenames': True,
        }

        if self.cookies_file and os.path.exists(self.cookies_file):
            opts['cookiefile'] = self.cookies_file

        if self.proxy:
            opts['proxy'] = self.proxy

        return opts

    def _get_download_opts(
            self,
            output_dir: str,
            quality: str = "high",
            is_audio: bool = False,
            progress_hook: Optional[Callable] = None
    ) -> Dict:
        """Yükləmə seçimlərini hazırla"""

        opts = self._get_base_opts()
        opts['outtmpl'] = f'{output_dir}/%(id)s_%(title).100s.%(ext)s'
        opts['writethumbnail'] = True

        if progress_hook:
            opts['progress_hooks'] = [progress_hook]

        jpg_converter = {'key': 'FFmpegThumbnailsConvertor', 'format': 'jpg'}

        if is_audio:
            audio_quality = self.AUDIO_QUALITY.get(quality, '192')
            opts['format'] = 'bestaudio[ext=m4a]/bestaudio/best'
            opts['postprocessors'] = [
                {
                    'key': 'FFmpegExtractAudio',
                    'preferredcodec': 'mp3',
                    'preferredquality': audio_quality,
                },
                jpg_converter,
                {'key': 'EmbedThumbnail', 'already_have_thumbnail': False},
                {'key': 'FFmpegMetadata', 'add_metadata': True}
            ]
        else:
            preset = self.QUALITY_PRESETS.get(quality, self.QUALITY_PRESETS['high'])
            opts['format'] = preset['format']
            opts['merge_output_format'] = 'mp4'
            opts['postprocessors'] = [
                {'key': 'FFmpegVideoRemuxer', 'preferedformat': 'mp4'},
                jpg_converter,
                {'key': 'EmbedThumbnail', 'already_have_thumbnail': False},
                {'key': 'FFmpegMetadata', 'add_metadata': True}
            ]

        return opts

    def _find_files(self, directory: str, is_audio: bool) -> tuple:
        """Yüklənmiş faylları tap"""
        media_path = None
        thumb_path = None

        if not os.path.exists(directory):
            return None, None

        all_files = []
        for root, _, files in os.walk(directory):
            for f in files:
                full_path = os.path.join(root, f)
                if os.path.isfile(full_path):
                    all_files.append(full_path)

        if not all_files:
            return None, None

        # Media faylı
        if is_audio:
            media_ext = ('.mp3', '.m4a', '.aac', '.opus', '.ogg', '.flac', '.wav')
        else:
            media_ext = ('.mp4', '.mkv', '.webm', '.avi', '.mov', '.m4v')

        media_files = [f for f in all_files if f.lower().endswith(media_ext)]
        if media_files:
            media_path = max(media_files, key=os.path.getsize)

        # Thumbnail
        image_ext = ('.jpg', '.jpeg', '.png', '.webp')
        image_files = [f for f in all_files if f.lower().endswith(image_ext)]
        if image_files:
            jpg_files = [f for f in image_files if f.lower().endswith(('.jpg', '.jpeg'))]
            thumb_path = max(jpg_files or image_files, key=os.path.getsize)

        return media_path, thumb_path

    def _parse_error(self, error: Exception) -> str:
        """Xəta mesajını parse et"""
        error_msg = str(error)

        if 'Video unavailable' in error_msg:
            return "Video mövcud deyil və ya silinib"
        elif 'Private video' in error_msg:
            return "Bu video özəldir (private)"
        elif 'Sign in' in error_msg or 'age' in error_msg.lower():
            return "Yaş məhdudiyyətli video. Cookies lazımdır"
        elif 'copyright' in error_msg.lower():
            return "Video müəllif hüquqları səbəbindən bloklanıb"
        elif 'Geo' in error_msg or 'country' in error_msg.lower():
            return "Video bu ölkədə əlçatan deyil"
        elif 'format' in error_msg.lower():
            return "İstənilən format mövcud deyil"

        return error_msg[:200]

    def _retry_operation(self, operation: Callable, *args, **kwargs) -> Any:
        """Retry ilə əməliyyat"""
        last_error = None

        for attempt in range(self.max_retries):
            try:
                return operation(*args, **kwargs)
            except Exception as e:
                last_error = e
                if attempt < self.max_retries - 1:
                    time.sleep(self.retry_delay * (attempt + 1))

        raise last_error

    def get_info(self, url: str) -> Dict[str, Any]:
        """
        🔍 Video məlumatlarını al

        Args:
            url: Video URL

        Returns:
            Video metadata dictionary
        """
        opts = self._get_base_opts()
        opts['skip_download'] = True

        def _extract():
            with yt_dlp.YoutubeDL(opts) as ydl:
                return ydl.extract_info(url, download=False)

        try:
            info = self._retry_operation(_extract)

            return {
                'success': True,
                'id': info.get('id', ''),
                'title': info.get('title', 'Unknown'),
                'description': info.get('description', ''),
                'duration': info.get('duration', 0),
                'uploader': info.get('uploader', info.get('channel', 'Unknown')),
                'view_count': info.get('view_count', 0),
                'like_count': info.get('like_count', 0),
                'upload_date': info.get('upload_date', ''),
                'thumbnail': info.get('thumbnail', ''),
                'webpage_url': info.get('webpage_url', url),
                'is_live': info.get('is_live', False),
            }
        except Exception as e:
            return {'success': False, 'error': self._parse_error(e)}

    def download_process(
            self,
            url: str,
            output_dir: str,
            quality: str = "high",
            is_audio: bool = False,
            progress_hook: Optional[Callable] = None
    ) -> Dict[str, Any]:
        """
        🐺 Əsas yükləmə prosesi

        Args:
            url: Video URL
            output_dir: Çıxış qovluğu
            quality: ultra/high/medium/low/lowest
            is_audio: True = MP3, False = MP4
            progress_hook: Progress callback

        Returns:
            {
                'success': True/False,
                'path': '/path/to/file',
                'thumb': '/path/to/thumb.jpg',
                'title': 'Video Title',
                'duration': 123,
                'filesize': 1234567,
                'error': None
            }
        """
        result = {
            'success': False,
            'path': None,
            'thumb': None,
            'title': 'Unknown',
            'duration': 0,
            'filesize': 0,
            'error': None
        }

        os.makedirs(output_dir, exist_ok=True)
        opts = self._get_download_opts(output_dir, quality, is_audio, progress_hook)

        def _download():
            with yt_dlp.YoutubeDL(opts) as ydl:
                return ydl.extract_info(url, download=True)

        try:
            info = self._retry_operation(_download)

            if not info:
                result['error'] = "Video məlumatları alına bilmədi"
                return result

            media_path, thumb_path = self._find_files(output_dir, is_audio)

            if not media_path or not os.path.exists(media_path):
                result['error'] = "Yüklənmiş fayl tapılmadı"
                return result

            result['success'] = True
            result['path'] = media_path
            result['thumb'] = thumb_path
            result['title'] = clean_filename(info.get('title', 'Video'))
            result['duration'] = info.get('duration', 0)
            result['filesize'] = os.path.getsize(media_path)
            result['metadata'] = {
                'id': info.get('id', ''),
                'uploader': info.get('uploader', ''),
                'webpage_url': info.get('webpage_url', url)
            }

            return result

        except Exception as e:
            result['error'] = self._parse_error(e)
            return result

    def download_video(
            self,
            url: str,
            output_dir: str,
            quality: str = "high",
            progress_hook: Optional[Callable] = None
    ) -> Dict[str, Any]:
        """🎬 Video yüklə"""
        return self.download_process(url, output_dir, quality, False, progress_hook)

    def download_audio(
            self,
            url: str,
            output_dir: str,
            quality: str = "high",
            progress_hook: Optional[Callable] = None
    ) -> Dict[str, Any]:
        """🎵 Audio yüklə"""
        return self.download_process(url, output_dir, quality, True, progress_hook)

    def is_valid_url(self, url: str) -> bool:
        """✅ URL yoxla"""
        return is_valid_url(url)

    def batch_download(
            self,
            urls: List[str],
            output_dir: str,
            quality: str = "high",
            is_audio: bool = False,
            max_workers: int = 3
    ) -> List[Dict[str, Any]]:
        """📦 Toplu yükləmə"""

        def _download_single(url):
            sub_dir = os.path.join(output_dir, str(hash(url))[-8:])
            os.makedirs(sub_dir, exist_ok=True)
            return self.download_process(url, sub_dir, quality, is_audio)

        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            return list(executor.map(_download_single, urls))


# Alias
WolfDownloader = YouTube
Wolf = YouTube