# ==============================================================
# ytdlp.py — כל הלוגיקה הקשורה ל-yt-dlp
#   - שליפת ערוץ (fetch_channel_with_ytdlp)
#   - הורדת תמונת ערוץ (download_channel_image)
#   - בדיקת גרסה (get_ytdlp_version)
#   - עדכון אוטומטי (update_ytdlp)
# ==============================================================

import os
import ssl
import json
import platform
import subprocess
import datetime
import urllib.request

from py.config import BASE_DIR, IMG_DIR


# ─── SSL Context (ללא אימות — עוקף חסימות) ───────────────────
def _ssl_ctx():
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode    = ssl.CERT_NONE
    return ctx


def _ytdlp_exe():
    return os.path.join(BASE_DIR, 'yt-dlp.exe')


def _creationflags():
    return subprocess.CREATE_NO_WINDOW if platform.system() == 'Windows' else 0


# ─── תמונת ערוץ ───────────────────────────────────────────────
def download_channel_image(url, channel_id):
    """מוריד תמונת ערוץ מקומית — עוקף חסימת נטפרי על yt3.ggpht.com"""
    if not url or not channel_id:
        return None
    try:
        os.makedirs(IMG_DIR, exist_ok=True)
        safe_id  = ''.join(c for c in channel_id if c.isalnum() or c in '-_')
        filename = f"{safe_id}.jpg"
        filepath = os.path.join(IMG_DIR, filename)
        if os.path.exists(filepath) and os.path.getsize(filepath) > 1024:
            return f"/{os.path.basename(IMG_DIR)}/{filename}"
        req  = urllib.request.Request(url, headers={'User-Agent': 'Mozilla/5.0'})
        data = urllib.request.urlopen(req, context=_ssl_ctx(), timeout=10).read()
        if len(data) > 1024:
            with open(filepath, 'wb') as f:
                f.write(data)
            print(f"  [IMG] Saved: {filename}")
            return f"/{os.path.basename(IMG_DIR)}/{filename}"
    except Exception as e:
        print(f"  [IMG] Failed: {e}")
    return None


# ─── שליפת ערוץ ───────────────────────────────────────────────
def fetch_channel_with_ytdlp(url, max_results):
    exe_name = _ytdlp_exe()
    if not os.path.exists(exe_name):
        return None, "הקובץ 'yt-dlp.exe' לא נמצא בתיקיית התוכנה."

    clean_url = url.strip()
    if '@' in clean_url and not clean_url.endswith('/videos'):
        clean_url += ('videos' if clean_url.endswith('/') else '/videos')

    cmd = [
        exe_name, '-J', '--flat-playlist', '--no-warnings', '--ignore-errors',
        '--no-check-certificate', '--prefer-free-formats',
        '--extractor-args', 'youtubetab:approximate_date',
        '--extractor-args', 'youtube:player_client=android,web',
        '--add-header', 'Accept-Language: he,he-IL;q=0.9,en-US;q=0.8,en;q=0.7',
        '--playlist-end', str(max_results if max_results > 0 else 1500),
        clean_url
    ]
    print(f"  [EXEC] {' '.join(cmd)}")

    try:
        result = subprocess.run(
            cmd, capture_output=True, text=True,
            encoding='utf-8', errors='replace',
            creationflags=_creationflags()
        )
        output = result.stdout.strip()
        if not output:
            error_msg = result.stderr.strip() or "No output from tool"
            print(f"  [ERROR] {error_msg}")
            return None, f"שגיאה: הכלי לא החזיר נתונים. ({error_msg[:100]})"
        info = json.loads(output)
    except json.JSONDecodeError:
        return None, "שגיאה: פלט לא תקין מהכלי. ייתכן ונדרש עדכון ל-yt-dlp."
    except Exception as e:
        return None, f"שגיאה פנימית: {str(e)}"

    if not info or (isinstance(info, dict) and not info.get('entries') and not info.get('title')):
        # אם הוחזרה רשימה ריקה, נדפיס את השגיאה הנסתרת למסוף לצורך דיבוג
        if 'result' in locals() and result.stderr:
            print(f"  [DEBUG STDERR] {result.stderr.strip()}")
        return None, "לא נמצאו סרטונים. וודא שהקישור תקין."

    # תמונת ערוץ
    thumbnails   = info.get('thumbnails', [])
    channel_id   = info.get('channel_id') or info.get('uploader_id') or 'ch'
    avatar_thumb = next((t for t in thumbnails if 'avatar' in (t.get('id') or '').lower()), None)
    if not avatar_thumb:
        avatar_thumb = next((t for t in thumbnails if t.get('width') and t.get('height') and t['width'] == t['height']), None)
    if not avatar_thumb and thumbnails:
        avatar_thumb = thumbnails[0]
    raw_image_url = avatar_thumb['url'] if avatar_thumb else ''
    local_image   = download_channel_image(raw_image_url, channel_id) if raw_image_url else None
    image_url     = local_image or raw_image_url

    # עיבוד פרקים
    entries = info.get('entries', []) or []
    print(f"  [INFO] Processing {len(entries)} entries...")
    episodes = []

    for e in entries:
        if not e or not e.get('id'):
            continue
        video_id  = e.get('id')
        raw_date  = e.get('upload_date') or ''
        timestamp = e.get('timestamp') or e.get('release_timestamp')
        approx    = e.get('approximate_date') or ''

        if len(raw_date) == 8:
            pub_date = f"{raw_date[:4]}-{raw_date[4:6]}-{raw_date[6:]}T00:00:00Z"
        elif timestamp:
            pub_date = datetime.datetime.fromtimestamp(int(timestamp), tz=datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
        elif len(approx) == 8:
            pub_date = f"{approx[:4]}-{approx[4:6]}-{approx[6:]}T00:00:00Z"
        else:
            pub_date = ""

        duration_sec = e.get('duration')
        duration_str = ""
        if duration_sec:
            try:
                m, s = divmod(int(duration_sec), 60)
                h, m = divmod(m, 60)
                duration_str = f"{h}:{m:02d}:{s:02d}" if h > 0 else f"{m}:{s:02d}"
            except:
                pass

        episodes.append({
            'title':       e.get('title', 'ללא כותרת'),
            'description': e.get('description', ''),
            'pubDate':     pub_date,
            'image':       f"https://img.youtube.com/vi/{video_id}/mqdefault.jpg",
            'audioUrl':    f"https://www.youtube.com/watch?v={video_id}",
            'guid':        video_id,
            'duration':    duration_str,
        })

    raw_title = info.get('title', url)
    for suffix in [' - Videos', ' - Shorts', ' - Streams', ' - Playlists']:
        if raw_title.endswith(suffix):
            raw_title = raw_title[:-len(suffix)]
            break

    return {
        'title':           raw_title,
        'description':     info.get('description', ''),
        'image':           image_url,
        'link':            info.get('webpage_url', url),
        'subscribers':     info.get('channel_follower_count', None),
        'totalVideoCount': info.get('playlist_count', len(episodes)),
        'episodes':        episodes
    }, None


# ─── בדיקת קיום yt-dlp ────────────────────────────────────────
def get_ytdlp_status():
    """מחזיר {'exists': bool, 'version': str|None}"""
    exe = _ytdlp_exe()
    if not os.path.exists(exe):
        return {'exists': False, 'version': None}
    try:
        r = subprocess.run([exe, '--version'], capture_output=True, text=True,
                           timeout=8, creationflags=_creationflags())
        return {'exists': True, 'version': r.stdout.strip()}
    except Exception:
        return {'exists': True, 'version': None}


# ─── הורדת yt-dlp עם התקדמות ─────────────────────────────────
def download_ytdlp_with_progress(progress_callback):
    """
    מוריד את yt-dlp.exe העדכני מ-GitHub.
    progress_callback(pct, msg) — נקרא לאורך ההורדה.
    מחזיר {'success': True, 'version': str}
    """
    progress_callback(5, 'מתחבר ל-GitHub...')
    req = urllib.request.Request(
        'https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest',
        headers={'User-Agent': 'Mozilla/5.0', 'Accept': 'application/json'}
    )
    release = json.loads(urllib.request.urlopen(req, context=_ssl_ctx(), timeout=10).read())
    asset   = next((a for a in release.get('assets', []) if a['name'] == 'yt-dlp.exe'), None)
    if not asset:
        raise RuntimeError('לא נמצא קובץ yt-dlp.exe ב-GitHub')

    version    = release.get('tag_name', '').lstrip('v')
    total_size = asset.get('size', 0)
    progress_callback(10, f'מוריד yt-dlp {version}...')

    exe_name = _ytdlp_exe()
    tmp      = exe_name + '.tmp'

    req2 = urllib.request.Request(
        asset['browser_download_url'],
        headers={'User-Agent': 'Mozilla/5.0'}
    )
    response   = urllib.request.urlopen(req2, context=_ssl_ctx(), timeout=120)
    downloaded = 0
    chunk_size = 65536  # 64KB

    with open(tmp, 'wb') as f:
        while True:
            chunk = response.read(chunk_size)
            if not chunk:
                break
            f.write(chunk)
            downloaded += len(chunk)
            if total_size > 0:
                pct = int(10 + (downloaded / total_size) * 85)
                mb  = downloaded / 1048576
                progress_callback(min(pct, 95), f'מוריד... {mb:.1f} MB')

    progress_callback(97, 'מתקין...')
    os.replace(tmp, exe_name)
    progress_callback(100, f'✓ yt-dlp {version} הותקן בהצלחה')
    return {'success': True, 'version': version}



def get_ytdlp_version():
    """מחזיר {'current': ..., 'latest': ...} או זורק Exception"""
    exe_name = _ytdlp_exe()
    r = subprocess.run(
        [exe_name, '--version'], capture_output=True, text=True, timeout=10,
        creationflags=_creationflags()
    )
    current = r.stdout.strip()
    latest  = None
    try:
        req  = urllib.request.Request(
            'https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest',
            headers={'User-Agent': 'Mozilla/5.0', 'Accept': 'application/json'}
        )
        info   = json.loads(urllib.request.urlopen(req, context=_ssl_ctx(), timeout=8).read())
        latest = info.get('tag_name', '').lstrip('v')
    except Exception as e:
        print(f"  [YTDLP] GitHub check failed: {e}")
    return {'current': current, 'latest': latest}


# ─── עדכון yt-dlp ─────────────────────────────────────────────
def update_ytdlp():
    """מוריד את גרסת yt-dlp העדכנית מ-GitHub. מחזיר {'success': True, 'version': ...} או זורק Exception"""
    exe_name = _ytdlp_exe()
    req      = urllib.request.Request(
        'https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest',
        headers={'User-Agent': 'Mozilla/5.0', 'Accept': 'application/json'}
    )
    release = json.loads(urllib.request.urlopen(req, context=_ssl_ctx(), timeout=8).read())
    asset   = next((a for a in release.get('assets', []) if a['name'] == 'yt-dlp.exe'), None)
    if not asset:
        raise RuntimeError('לא נמצא קובץ להורדה')
    version = release.get('tag_name', '').lstrip('v')
    print(f"  [UPDATE] Downloading yt-dlp {version}...")
    req2 = urllib.request.Request(asset['browser_download_url'], headers={'User-Agent': 'Mozilla/5.0'})
    data = urllib.request.urlopen(req2, context=_ssl_ctx(), timeout=60).read()
    tmp  = exe_name + '.tmp'
    with open(tmp, 'wb') as f:
        f.write(data)
    os.replace(tmp, exe_name)
    print(f"  [UPDATE] Done: {version}")
    return {'success': True, 'version': version}