"""Abre tab nuevo en Chrome remoto, navega a URL, espera Page.loadEventFired."""

import json
import threading
import urllib.request
import urllib.parse
import websocket


def cdp_open_url_and_wait(
    debug_port: int,
    url: str,
    timeout_s: int = 30,
) -> str:
    """Crea tab nuevo en Chrome remoto, navega a url, espera Page.loadEventFired.

    Args:
        debug_port: Puerto de depuracion remota de Chrome (ej. 9222).
        url: URL a la que navegar.
        timeout_s: Timeout total en segundos para esperar el load event.

    Returns:
        tab_id (string) del tab recien creado.

    Raises:
        RuntimeError: Si Chrome no responde, la navegacion falla o se agota timeout.
    """
    encoded = urllib.parse.quote(url, safe=":/?#[]@!$&'()*+,;=%")
    new_tab_url = f"http://127.0.0.1:{debug_port}/json/new?{encoded}"

    req = urllib.request.Request(new_tab_url, method="PUT")
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            tab_info = json.loads(resp.read().decode())
    except Exception as e:
        raise RuntimeError(f"cdp_open_url_and_wait: no se pudo crear tab en port {debug_port}: {e}") from e

    tab_id = tab_info.get("id", "")
    ws_url = tab_info.get("webSocketDebuggerUrl", "")
    if not ws_url:
        raise RuntimeError(f"cdp_open_url_and_wait: tab sin webSocketDebuggerUrl: {tab_info}")

    load_event = threading.Event()
    errors = []

    def on_message(ws_app, message):
        try:
            msg = json.loads(message)
            if msg.get("method") == "Page.loadEventFired":
                load_event.set()
        except Exception:
            pass

    def on_error(ws_app, error):
        errors.append(str(error))
        load_event.set()

    def on_open(ws_app):
        ws_app.send(json.dumps({"id": 1, "method": "Page.enable", "params": {}}))

    ws = websocket.WebSocketApp(
        ws_url,
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
    )

    t = threading.Thread(target=ws.run_forever, daemon=True)
    t.start()

    fired = load_event.wait(timeout=timeout_s)
    ws.close()

    if errors:
        raise RuntimeError(f"cdp_open_url_and_wait: WS error: {errors[0]}")
    if not fired:
        raise RuntimeError(f"cdp_open_url_and_wait: timeout ({timeout_s}s) esperando Page.loadEventFired para {url}")

    return tab_id
