"""Helpers shared by the end-to-end tests: HTTP, sessions, UI waiters.

The suite drives the real server and the built webclient, so the helpers stay
deliberately small: create a session over REST, open it in the browser, type a
prompt, and wait for the tool cards the agent is supposed to produce.
"""

from __future__ import annotations

import json
import os
from urllib import request

# How long one agent turn may take. A real cloud model plans, thinks and calls
# tools, so this is minutes rather than seconds by design.
TURN_TIMEOUT_MS = int(os.environ.get("E2E_TURN_TIMEOUT_MS", "300000"))
# How long the fresh backend may take to answer /health.
SERVER_TIMEOUT = float(os.environ.get("E2E_SERVER_TIMEOUT", "120"))


def post_json(base_url: str, path: str, payload: dict) -> dict:
    data = json.dumps(payload).encode()
    req = request.Request(
        base_url + path,
        data=data,
        method="POST",
        headers={"Content-Type": "application/json"},
    )
    with request.urlopen(req, timeout=30) as resp:
        return json.loads(resp.read().decode())


def create_session(base_url: str, profile: str = "assistant") -> str:
    """Create a session as the anonymous admin (auth is off in the harness)."""
    return post_json(base_url, "/sessions", {"profile_id": profile})["session_id"]


def open_session(page, base_url: str, session_id: str) -> None:
    page.goto(f"{base_url}/#{session_id}", wait_until="domcontentloaded")
    page.wait_for_selector(".input-textarea", timeout=30_000)


def send_message(page, text: str) -> None:
    page.fill(".input-textarea", text)
    page.press(".input-textarea", "Enter")


def tool_card(page, name: str):
    return page.locator(f'.tool-card:has(.tool-name:text-is("{name}"))').first


def wait_for_tools(page, names: list[str], timeout_ms: int) -> None:
    """Wait until every named tool card exists and the turn has finished.

    ``.msg-meta-row`` is rendered only for a completed assistant message (the
    stats/timestamp row), so it is the end-of-turn marker the UI already owns.
    """
    for name in names:
        page.wait_for_selector(
            f'.tool-card:has(.tool-name:text-is("{name}"))',
            timeout=timeout_ms,
        )
    page.wait_for_selector(".msg-meta-row", timeout=timeout_ms)


def assert_ok(card) -> None:
    classes = card.get_attribute("class") or ""
    assert "is-success" in classes, f"tool card did not succeed: {classes}"


def result_text(card) -> str:
    return card.locator(".tool-result").text_content() or ""
