# ==============================================================
# handlers.py — MyHandler: כל ה-routes של השרת
# ==============================================================

import http.server
import json
import os
import ssl

import py.config as cfg
import py.downloader as downloader
from py.ytdlp import fetch_channel_with_ytdlp, get_ytdlp_version, update_ytdlp, get_ytdlp_status, download_ytdlp_with_progress


class MyHandler(http.server.SimpleHTTPRequestHandler):

    # ─── לוג — מסנן בקשות שגרתיות רועשות ───────────────────
    def log_message(self, fmt, *args):
        msg = str(args[0]) if args else ''
        # מסנן: קבצים סטטיים + heartbeat + בדיקות סטטוס הורדה
        if any(x in msg for x in ['/js/', '/styles.css', '/favicon.ico', '/api/heartbeat', '/api/download/status']):
            return
        super().log_message(fmt, *args)

    # ─── עזרים ───────────────────────────────────────────────
    def _cors_headers(self):
        self.send_header('Access-Control-Allow-Origin',  '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')

    def send_json(self, obj, status=200):
        body = json.dumps(obj, ensure_ascii=False).encode('utf-8')
        self.send_response(status)
        self.send_header('Content-Type',   'application/json; charset=utf-8')
        self.send_header('Content-Length', str(len(body)))
        self._cors_headers()
        self.end_headers()
        self.wfile.write(body)

    def do_OPTIONS(self):
        self.send_response(204)
        self._cors_headers()
        self.end_headers()

    # ─── GET ─────────────────────────────────────────────────
    def do_GET(self):

        # גיבוי נתונים
        if self.path == '/api/data':
            if os.path.exists(cfg.DATA_FILE):
                try:
                    with open(cfg.DATA_FILE, 'rb') as f:
                        content = f.read()
                    size_kb = len(content) / 1024
                    print(f"  [נתונים] טעינת ספרייה מהדיסק — {size_kb:.1f} KB")
                    self.send_response(200)
                    self.send_header('Content-Type', 'application/json; charset=utf-8')
                    self._cors_headers()
                    self.end_headers()
                    self.wfile.write(content)
                except Exception as e:
                    print(f"  [שגיאה] קריאת קובץ נתונים נכשלה: {e}")
                    self.send_json({'error': str(e)}, 500)
            else:
                print(f"  [נתונים] קובץ נתונים לא נמצא — מחזיר רשימה ריקה")
                self.send_json([])

        # סטטוס הורדות
        elif self.path == '/api/download/status':
            self.send_json(downloader.get_status())

        # גרסת yt-dlp
        elif self.path == '/api/ytdlp/version':
            try:
                result = get_ytdlp_version()
                print(f"  [גרסה] yt-dlp מקומי: {result.get('current','?')} | עדכנית: {result.get('latest','?')}")
                self.send_json(result)
            except Exception as e:
                print(f"  [שגיאה] לא ניתן לקרוא גרסת yt-dlp: {e}")
                self.send_json({'error': f'לא ניתן להריץ yt-dlp: {e}'})

        # סטטוס קיום yt-dlp
        elif self.path == '/api/ytdlp/status':
            try:
                self.send_json(get_ytdlp_status())
            except Exception as e:
                self.send_json({'exists': False, 'error': str(e)})

        # סטטוס קיום ffmpeg
        elif self.path == '/api/ffmpeg/status':
            try:
                ffmpeg_path = os.path.join(cfg.BASE_DIR, 'ffmpeg.exe')
                exists = os.path.isfile(ffmpeg_path)
                self.send_json({'exists': exists})
            except Exception as e:
                self.send_json({'exists': False, 'error': str(e)})

        # הורדת/עדכון yt-dlp עם SSE התקדמות
        elif self.path == '/api/ytdlp/download':
            self.send_response(200)
            self.send_header('Content-Type',  'text/event-stream; charset=utf-8')
            self.send_header('Cache-Control', 'no-cache')
            self.send_header('Connection',    'keep-alive')
            self._cors_headers()
            self.end_headers()

            def send_event(pct, msg):
                try:
                    line = f"data: {json.dumps({'pct': pct, 'msg': msg}, ensure_ascii=False)}\n\n"
                    self.wfile.write(line.encode('utf-8'))
                    self.wfile.flush()
                except Exception:
                    pass

            try:
                print(f"\n[הורדה] מתחיל הורדת yt-dlp...")
                result = download_ytdlp_with_progress(send_event)
                print(f"  [הורדה] הצלחה — גרסה: {result.get('version','?')}")
            except Exception as e:
                print(f"  [שגיאה] הורדת yt-dlp נכשלה: {e}")
                send_event(-1, f'שגיאה: {str(e)}')

        # תמונות ערוץ
        elif self.path.startswith('/channel-images/'):
            filename = self.path[len('/channel-images/'):]
            filepath = os.path.join(cfg.IMG_DIR, filename)
            if os.path.exists(filepath):
                try:
                    with open(filepath, 'rb') as f:
                        content = f.read()
                    self.send_response(200)
                    self.send_header('Content-Type',  'image/jpeg')
                    self.send_header('Cache-Control', 'public, max-age=86400')
                    self._cors_headers()
                    self.end_headers()
                    self.wfile.write(content)
                except Exception as e:
                    print(f"  [שגיאה] טעינת תמונת ערוץ נכשלה ({filename}): {e}")
                    self.send_json({'error': str(e)}, 500)
            else:
                self.send_response(404); self.end_headers()

        else:
            super().do_GET()

    # ─── POST ────────────────────────────────────────────────
    def do_POST(self):
        import time
        import datetime
        import threading

        length = int(self.headers.get('Content-Length', 0))
        raw    = self.rfile.read(length)

        # Shutdown
        if self.path == '/api/shutdown':
            cfg._pending_shutdown = True
            def _do_shutdown():
                time.sleep(5)
                if cfg._pending_shutdown:
                    print(f"\n[סגירה] הדפדפן נסגר — השרת נעצר בעוד 5 שניות")
                    print(f"        {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
                    os._exit(0)
            threading.Thread(target=_do_shutdown, daemon=True).start()
            self.send_json({'ok': True})
            return

        # Heartbeat
        if self.path == '/api/heartbeat':
            cfg._last_heartbeat   = time.time()
            cfg._pending_shutdown = False
            self.send_json({'ok': True})
            return

        # עדכון yt-dlp
        if self.path == '/api/ytdlp/update':
            try:
                print(f"\n[עדכון] מתחיל הורדת גרסה עדכנית של yt-dlp...")
                result = update_ytdlp()
                if result.get('success'):
                    print(f"  [עדכון] הצלחה — גרסה חדשה: {result.get('version','?')}")
                else:
                    print(f"  [עדכון] נכשל: {result.get('error','שגיאה לא ידועה')}")
                self.send_json(result)
            except Exception as e:
                print(f"  [שגיאה] עדכון yt-dlp נכשל: {e}")
                self.send_json({'error': str(e)})
            return

        # Parse JSON body
        try:
            data = json.loads(raw) if raw else {}
        except:
            self.send_json({'error': 'JSON לא תקין'}, 400); return

        # התחלת הורדה
        if self.path == '/api/download/start':
            video_id = data.get('videoId')
            category = data.get('category', 'כללי')
            channel  = data.get('channel', 'לא ידוע')
            is_playlist = data.get('isPlaylist', False)
            
            if not video_id:
                self.send_json({'error': 'חסר videoId או קישור'}, 400)
                return
                
            job_id = downloader.start_download(video_id, category, channel, is_playlist)
            display_id = video_id[:25] + "..." if len(video_id) > 25 else video_id
            print(f"  [הורדה] התקבלה בקשה: {display_id} -> {category}/{channel} (פלייליסט: {is_playlist})")
            self.send_json({"success": True, "jobId": job_id})

        # ביטול הורדה
        elif self.path == '/api/download/cancel':
            job_id = data.get('jobId')
            success = downloader.cancel_download(job_id)
            print(f"  [הורדה] משימה {job_id[:8]} בוטלה: {success}")
            self.send_json({"success": success})
            
        # מחיקת הורדה שהסתיימה מהרשימה
        elif self.path == '/api/download/clear':
            job_id = data.get('jobId')
            success = downloader.clear_completed(job_id)
            self.send_json({"success": success})

        # שמירת נתונים
        elif self.path == '/api/data':
            try:
                with open(cfg.DATA_FILE, 'w', encoding='utf-8') as f:
                    json.dump(data, f, ensure_ascii=False, indent=2)
                size_kb = os.path.getsize(cfg.DATA_FILE) / 1024
                print(f"  [שמירה] ספרייה נשמרה לדיסק — {size_kb:.1f} KB")
                self.send_json({'success': True})
            except Exception as e:
                print(f"  [שגיאה] שמירת נתונים נכשלה: {e}")
                self.send_json({'error': str(e)}, 500)

        # שליפת ערוץ YouTube
        elif self.path == '/api/youtube/fetch-all':
            url         = data.get('url', '').strip()
            max_results = int(data.get('maxEpisodes', 1500))
            print(f"\n[שליפה] {url}")
            print(f"         מביא עד {max_results} סרטונים אחרונים...")
            info, err = fetch_channel_with_ytdlp(url, max_results)
            if err:
                print(f"  [שגיאה] שליפה נכשלה: {err}")
                self.send_json({'error': err}, 400)
            else:
                count = len(info['episodes'])
                print(f"  [הצלחה] '{info['title']}' — נמצאו {count} סרטונים")
                self.send_json(info)