#!/usr/bin/env python3
"""
Test talkingwidget.ai with microphone permissions pre-granted via CDP.
Simulates a real device clicking the mic overlay button to start a call.

Strategy:
1. Launch Chromium directly with --use-fake-device-for-media-stream flags
2. Connect to it via CDP using connect_over_cdp()
3. This avoids the Playwright headless-shell/pipe crash
"""

import time
import json
import os
import subprocess
import signal
import sys
from playwright.sync_api import sync_playwright

SCREENSHOT_DIR = "/mnt/e/genesis-system/qa_reports"
os.makedirs(SCREENSHOT_DIR, exist_ok=True)

CONSOLE_LOGS = []
JS_ERRORS = []

CHROME_BIN = "/home/authentic88/.cache/ms-playwright/chromium-1200/chrome-linux64/chrome"
CDP_PORT = 9224
PROFILE_DIR = "/tmp/chrome-talkingwidget-test"

def launch_chrome():
    """Launch Chrome with fake media devices and return the process."""
    os.makedirs(PROFILE_DIR, exist_ok=True)
    cmd = [
        CHROME_BIN,
        "--headless=new",
        "--no-sandbox",
        "--disable-setuid-sandbox",
        "--disable-dev-shm-usage",
        "--disable-gpu",
        "--use-fake-ui-for-media-stream",       # Auto-grant mic/camera permission dialogs
        "--use-fake-device-for-media-stream",   # Use fake audio/video device
        "--allow-running-insecure-content",
        f"--remote-debugging-port={CDP_PORT}",
        f"--user-data-dir={PROFILE_DIR}",
        "about:blank",
    ]
    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.DEVNULL,
        stderr=subprocess.DEVNULL,
    )
    return proc

def run_test():
    print(f"\n=== Launching Chrome with fake media device on CDP port {CDP_PORT} ===")
    chrome_proc = launch_chrome()

    # Wait for Chrome to be ready
    import urllib.request
    for i in range(10):
        time.sleep(1)
        try:
            urllib.request.urlopen(f"http://localhost:{CDP_PORT}/json/version", timeout=2)
            print(f"Chrome ready after {i+1}s")
            break
        except Exception:
            print(f"  Waiting for Chrome... {i+1}s")
    else:
        print("ERROR: Chrome did not start in time")
        chrome_proc.kill()
        return

    with sync_playwright() as p:
        print(f"Connecting to Chrome via CDP at ws://localhost:{CDP_PORT}")
        browser = p.chromium.connect_over_cdp(f"http://localhost:{CDP_PORT}")

        # Get or create a context
        contexts = browser.contexts
        if contexts:
            context = contexts[0]
        else:
            context = browser.new_context()

        # Grant permissions for talkingwidget.ai
        context.grant_permissions(["microphone", "camera"], origin="https://talkingwidget.ai")

        page = context.new_page()

        # Capture console logs
        def handle_console(msg):
            entry = f"[{msg.type.upper()}] {msg.text}"
            CONSOLE_LOGS.append(entry)
            # Print interesting ones
            text_lower = msg.text.lower()
            if any(k in text_lower for k in ["simli", "telnyx", "usermedia", "getusermedia", "error", "connect", "stream", "avatar", "call"]):
                print(f"  CONSOLE: {entry}")

        def handle_js_error(err):
            entry = f"[JS_ERROR] {err.message}"
            JS_ERRORS.append(entry)
            print(f"  JS_ERROR: {entry}")

        page.on("console", handle_console)
        page.on("pageerror", handle_js_error)

        # ---- STEP 1: Navigate ----
        print("\n=== STEP 1: Navigate to https://talkingwidget.ai ===")
        try:
            page.goto("https://talkingwidget.ai", timeout=30000, wait_until="domcontentloaded")
            print(f"URL: {page.url}")
            print(f"Title: {page.title()}")
        except Exception as e:
            print(f"Navigation error: {e}")

        # ---- STEP 2: Wait for full load ----
        print("\n=== STEP 2: Wait 6 seconds for full load ===")
        time.sleep(6)
        print(f"URL after load: {page.url}")

        # ---- STEP 3: Initial Screenshot ----
        print("\n=== STEP 3: Screenshot — Initial State ===")
        shot1 = f"{SCREENSHOT_DIR}/talkingwidget_01_initial.png"
        try:
            page.screenshot(path=shot1, full_page=False)
            print(f"Screenshot saved: {shot1}")
        except Exception as e:
            print(f"Screenshot error: {e}")

        # Check page elements
        overlay = page.query_selector("#avatar-idle-overlay")
        avatar_stage = page.query_selector("#avatar-stage")
        simli_vid = page.query_selector("#simli-vid")
        print(f"\n  #avatar-idle-overlay: {'FOUND' if overlay else 'NOT FOUND'}")
        print(f"  #avatar-stage: {'FOUND' if avatar_stage else 'NOT FOUND'}")
        print(f"  #simli-vid: {'FOUND' if simli_vid else 'NOT FOUND'}")

        # Get body text snippet
        try:
            body_text = page.evaluate("document.body.innerText.substring(0, 300)")
            print(f"\n  Body text: {body_text}")
        except Exception as e:
            print(f"  Body text error: {e}")

        # Check getUserMedia support
        try:
            gum_result = page.evaluate("""
                typeof navigator.mediaDevices !== 'undefined' &&
                typeof navigator.mediaDevices.getUserMedia !== 'undefined'
            """)
            print(f"\n  getUserMedia available: {gum_result}")

            # Actually try to get user media to confirm fake device works
            gum_test = page.evaluate("""
                new Promise(async (resolve) => {
                    try {
                        const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: false});
                        const tracks = stream.getAudioTracks();
                        resolve({success: true, tracks: tracks.length, label: tracks[0]?.label || 'no label'});
                        stream.getTracks().forEach(t => t.stop());
                    } catch(e) {
                        resolve({success: false, error: e.message, name: e.name});
                    }
                })
            """)
            print(f"  getUserMedia test: {gum_test}")
        except Exception as e:
            print(f"  getUserMedia test error: {e}")

        # ---- STEP 4: Click mic overlay ----
        print("\n=== STEP 4: Click #avatar-idle-overlay to start call ===")
        click_success = False
        if overlay:
            try:
                overlay.click()
                print("  Clicked #avatar-idle-overlay")
                click_success = True
            except Exception as e:
                print(f"  Click error: {e}")

        if not click_success:
            print("  Trying JS click fallback...")
            try:
                result = page.evaluate("""
                    const el = document.getElementById('avatar-idle-overlay');
                    if (el) { el.click(); return 'clicked'; }
                    return 'not found';
                """)
                print(f"  JS click result: {result}")
            except Exception as e:
                print(f"  JS click error: {e}")

        # ---- STEP 5: Wait 8 seconds ----
        print("\n=== STEP 5: Wait 8 seconds for call to connect ===")
        for i in range(4):
            time.sleep(2)
            elapsed = (i + 1) * 2
            # Filter key logs
            key_logs = [l for l in CONSOLE_LOGS[-20:] if any(k in l.lower() for k in
                       ["simli", "telnyx", "usermedia", "connect", "stream", "error", "avatar", "call", "webrtc"])]
            if key_logs:
                print(f"  {elapsed}s — Key logs: {key_logs[-3:]}")
            else:
                print(f"  {elapsed}s — no key logs yet (total: {len(CONSOLE_LOGS)})")

        # ---- STEP 6: Screenshot after click ----
        print("\n=== STEP 6: Screenshot — After Click ===")
        shot2 = f"{SCREENSHOT_DIR}/talkingwidget_02_after_click.png"
        try:
            page.screenshot(path=shot2, full_page=False)
            print(f"Screenshot saved: {shot2}")
        except Exception as e:
            print(f"Screenshot error: {e}")

        # ---- STEP 7: Console analysis ----
        print("\n=== STEP 7: Console Analysis ===")

        simli_connected = any("[Simli] Session connected" in l for l in CONSOLE_LOGS)
        simli_stream_live = any("[Simli] Avatar stream live" in l for l in CONSOLE_LOGS)
        simli_lip_sync = any("[Simli] Lip sync track connected" in l for l in CONSOLE_LOGS)

        getusermedia_logs = [l for l in CONSOLE_LOGS if "getUserMedia" in l or "usermedia" in l.lower()]
        telnyx_logs = [l for l in CONSOLE_LOGS if "telnyx" in l.lower() or "Telnyx" in l]
        simli_logs = [l for l in CONSOLE_LOGS if "simli" in l.lower() or "Simli" in l]
        error_logs = [l for l in CONSOLE_LOGS if "error" in l.lower() or "ERROR" in l]

        print(f"\n  --- Simli ---")
        print(f"  [Simli] Session connected: {simli_connected}")
        print(f"  [Simli] Avatar stream live: {simli_stream_live}")
        print(f"  [Simli] Lip sync track connected: {simli_lip_sync}")
        if simli_logs:
            print(f"  All Simli logs:")
            for l in simli_logs:
                print(f"    {l}")

        print(f"\n  --- getUserMedia ---")
        if getusermedia_logs:
            for l in getusermedia_logs:
                print(f"    {l}")
        else:
            print(f"    No getUserMedia logs")

        print(f"\n  --- Telnyx ---")
        if telnyx_logs:
            for l in telnyx_logs:
                print(f"    {l}")
        else:
            print(f"    No Telnyx logs")

        print(f"\n  --- Errors ---")
        if error_logs:
            for l in error_logs[:20]:
                print(f"    {l}")
        else:
            print(f"    No error logs")

        # ---- STEP 8: JS State ----
        print("\n=== STEP 8: JS State Check ===")
        try:
            js_state = page.evaluate("""
            JSON.stringify({
                inCall: document.getElementById('avatar-stage')?.classList?.contains('in-call'),
                simliVidExists: !!document.getElementById('simli-vid'),
                simliVidDisplay: document.getElementById('simli-vid')?.style?.display,
                simliVidHasStream: !!document.getElementById('simli-vid')?.srcObject,
                avatarStageClasses: document.getElementById('avatar-stage')?.className,
                overlayVisible: (function() {
                    const el = document.getElementById('avatar-idle-overlay');
                    if (!el) return false;
                    return window.getComputedStyle(el).display !== 'none';
                })(),
                bodyClasses: document.body.className,
                allElementIds: Array.from(document.querySelectorAll('[id]')).map(e => e.id).slice(0, 30),
            })
            """)
            state = json.loads(js_state)
            print(f"\n  inCall: {state.get('inCall')}")
            print(f"  simliVidExists: {state.get('simliVidExists')}")
            print(f"  simliVidDisplay: {state.get('simliVidDisplay')}")
            print(f"  simliVidHasStream: {state.get('simliVidHasStream')}")
            print(f"  avatarStageClasses: {state.get('avatarStageClasses')}")
            print(f"  overlayVisible: {state.get('overlayVisible')}")
            print(f"  bodyClasses: {state.get('bodyClasses')}")
            print(f"  Element IDs on page: {state.get('allElementIds')}")
        except Exception as e:
            print(f"  JS state error: {e}")

        # ---- STEP 9: Final Screenshot ----
        print("\n=== STEP 9: Final Screenshot ===")
        shot3 = f"{SCREENSHOT_DIR}/talkingwidget_03_final.png"
        try:
            page.screenshot(path=shot3, full_page=False)
            print(f"Screenshot saved: {shot3}")
        except Exception as e:
            print(f"Screenshot error: {e}")

        # ---- FULL LOG DUMP ----
        print("\n=== FULL CONSOLE LOG DUMP ===")
        print(f"Total console entries: {len(CONSOLE_LOGS)}")
        for entry in CONSOLE_LOGS:
            print(f"  {entry}")

        print("\n=== JS ERRORS ===")
        if JS_ERRORS:
            for entry in JS_ERRORS:
                print(f"  {entry}")
        else:
            print("  None")

        # ---- SUMMARY ----
        print("\n" + "="*60)
        print("SUMMARY")
        print("="*60)
        print(f"  Page loaded:              YES ({page.url})")
        print(f"  getUserMedia errors:      {bool([l for l in CONSOLE_LOGS if 'getusermedia' in l.lower() and 'error' in l.lower()])}")
        print(f"  Telnyx call connected:    {any('connect' in l.lower() for l in telnyx_logs)}")
        print(f"  Simli session connected:  {simli_connected}")
        print(f"  Simli avatar stream live: {simli_stream_live}")
        print(f"  Simli lip sync:           {simli_lip_sync}")
        print(f"  JS inCall=true:           {state.get('inCall') if 'state' in dir() else 'N/A'}")
        print(f"  simli-vid has srcObject:  {state.get('simliVidHasStream') if 'state' in dir() else 'N/A'}")
        print(f"  Screenshots:              {shot1}, {shot2}, {shot3}")
        print("="*60)

        browser.close()

    # Cleanup
    chrome_proc.terminate()
    chrome_proc.wait(timeout=5)
    print("\nChrome process terminated.")

if __name__ == "__main__":
    run_test()
