#!/usr/bin/env python3
"""DAZN Network Capture v3 - Chrome CDP con websocket sincrono (FIXED ORIGINS)"""
import json
import time
import os
import sys
import subprocess
import threading
import tempfile
from datetime import datetime

if sys.platform == 'win32':
    try:
        sys.stdout.reconfigure(encoding='utf-8', errors='replace')
        sys.stderr.reconfigure(encoding='utf-8', errors='replace')
    except:
        pass

import websocket
import requests as http_requests

SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
OUTPUT_FILE = os.path.join(SCRIPT_DIR, "captured_requests.json")
CHROME_PATH = r"C:\Program Files\Google\Chrome\Application\chrome.exe"
DEBUG_PORT = 9222

captured = []

def start_chrome():
    user_data = tempfile.mkdtemp(prefix="dazn_cap_")
    cmd = [
        CHROME_PATH,
        f"--remote-debugging-port={DEBUG_PORT}",
        f"--user-data-dir={user_data}",
        "--remote-allow-origins=*",
        "--no-first-run",
        "--no-default-browser-check",
        "--disable-default-apps",
        "https://www.dazn.com/it-IT/account/signin"
    ]
    proc = subprocess.Popen(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    print(f"[OK] Chrome avviato (PID: {proc.pid})")
    return proc

def get_ws_url():
    for _ in range(30):
        try:
            r = http_requests.get(f"http://127.0.0.1:{DEBUG_PORT}/json", timeout=2)
            tabs = r.json()
            for tab in tabs:
                if tab.get("type") == "page":
                    return tab["webSocketDebuggerUrl"]
        except:
            pass
        time.sleep(0.5)
    return None

def is_api_call(url):
    ul = url.lower()
    return any(k in ul for k in [
        'indazn.com', 'playback', 'license', 'authentication',
        'widevine', 'drm', 'eligibility', 'heartbeat',
        'concurrency', 'entitlement', '/v5/', '/v6/',
        'token', 'device', 'signin'
    ])

def listen_cdp(ws_url, duration=180):
    """Ascolta eventi CDP per `duration` secondi"""
    ws = websocket.create_connection(ws_url, timeout=5)
    
    # Abilita Network
    ws.send(json.dumps({"id": 1, "method": "Network.enable", "params": {}}))
    resp = ws.recv()
    print("[OK] Network monitoring attivo!")
    print(f"[*] Catturo per {duration}s. Logga e vai su un canale live!\n")
    
    ws.settimeout(1.0)  # timeout per recv() cosi il loop non blocca
    
    start = time.time()
    last_report = 0
    
    while time.time() - start < duration:
        try:
            msg = ws.recv()
            data = json.loads(msg)
            method = data.get("method", "")
            params = data.get("params", {})
            
            if method == "Network.requestWillBeSent":
                req = params.get("request", {})
                url = req.get("url", "")
                http_method = req.get("method", "GET")
                headers = req.get("headers", {})
                post_data = req.get("postData")
                
                entry = {
                    "rid": params.get("requestId", ""),
                    "ts": datetime.now().isoformat(),
                    "url": url,
                    "method": http_method,
                    "headers": headers,
                    "post_data": None,
                }
                if post_data:
                    try:
                        entry["post_data"] = json.loads(post_data)
                    except:
                        entry["post_data"] = post_data[:1000]
                
                captured.append(entry)
                
                if is_api_call(url):
                    print(f"[{datetime.now().strftime('%H:%M:%S')}] >>> {http_method:4s} {url[:140]}")
            
            elif method == "Network.responseReceived":
                resp = params.get("response", {})
                url = resp.get("url", "")
                status = resp.get("status", 0)
                rid = params.get("requestId", "")
                
                for e in reversed(captured):
                    if e.get("rid") == rid:
                        e["response_status"] = status
                        e["response_headers"] = resp.get("headers", {})
                        break
                
                if is_api_call(url):
                    print(f"             <<< {status} {'OK' if status<400 else 'ERR'} {url[:120]}")
                    
                    # Recupera response body per le API call
                    try:
                        ws.send(json.dumps({
                            "id": 9000 + len(captured),
                            "method": "Network.getResponseBody",
                            "params": {"requestId": rid}
                        }))
                    except:
                        pass
            
            elif "id" in data and "result" in data:
                # Risposta a getResponseBody
                result = data.get("result", {})
                body = result.get("body", "")
                if body:
                    # Trova l'ultima entry senza response_body
                    for e in reversed(captured):
                        if is_api_call(e.get("url", "")) and "response_body" not in e and "response_status" in e:
                            try:
                                e["response_body"] = json.loads(body)
                            except:
                                e["response_body"] = body[:2000]
                            break
                            
        except websocket.WebSocketTimeoutException:
            pass
        except Exception as e:
            pass
        
        elapsed = int(time.time() - start)
        if elapsed - last_report >= 30:
            last_report = elapsed
            api_count = sum(1 for r in captured if is_api_call(r.get("url", "")))
            print(f"  ... {elapsed}s - {len(captured)} totali, {api_count} API DAZN")
    
    ws.close()

def save_results():
    api_reqs = []
    for r in captured:
        if is_api_call(r.get("url", "")):
            clean = {k: v for k, v in r.items() if k != "rid"}
            api_reqs.append(clean)
    
    with open(OUTPUT_FILE, 'w', encoding='utf-8') as f:
        json.dump({
            "capture_time": datetime.now().isoformat(),
            "total": len(captured),
            "api_count": len(api_reqs),
            "requests": api_reqs
        }, f, indent=2, ensure_ascii=False, default=str)
    
    print(f"\n[SALVATO] {len(api_reqs)} richieste API in captured_requests.json")

def main():
    print("=" * 60)
    print("  DAZN Network Capture v3 (Chrome CDP)")
    print("=" * 60)
    print("\n  Chrome si apre. Logga e vai su un canale live.")
    print("  Catturo per 3 minuti poi salvo.\n")
    
    chrome = start_chrome()
    time.sleep(3)
    
    ws_url = get_ws_url()
    if not ws_url:
        print("[ERRORE] Non trovo Chrome CDP!")
        chrome.kill()
        return
    
    print(f"[OK] Connesso a Chrome")
    
    try:
        listen_cdp(ws_url, duration=180)
    except KeyboardInterrupt:
        print("\n[*] Interrotto dall'utente")
    
    save_results()
    
    print("[*] Chiudo Chrome...")
    try:
        chrome.terminate()
        chrome.wait(timeout=5)
    except:
        try: chrome.kill()
        except: pass
    
    print("[FINE]")

if __name__ == "__main__":
    main()
