"""HTTP wrapper for the DeskClaw exam server API."""

from __future__ import annotations

import time
from typing import Any

import httpx


class DeskClawAPI:
    """Thin HTTP client targeting a DeskClaw Dashboard server."""

    def __init__(self, server_url: str, timeout: float = 30.0) -> None:
        self.base = server_url.rstrip("/")
        self._client = httpx.Client(base_url=self.base, timeout=timeout)

    def health(self) -> dict[str, Any]:
        r = self._client.get("/api/v1/health")
        r.raise_for_status()
        return r.json()

    def register_adapter(
        self,
        *,
        name: str,
        url: str,
        protocol: str = "openai",
        capabilities: list[str] | None = None,
        auth_token: str | None = None,
    ) -> dict[str, Any]:
        payload: dict[str, Any] = {
            "name": name,
            "url": url,
            "protocol": protocol,
            "capabilities": capabilities or ["text_generation"],
        }
        if auth_token:
            payload["auth_token"] = auth_token

        r = self._client.post("/api/v1/adapters", json=payload)
        r.raise_for_status()
        return r.json()

    def list_adapters(self) -> dict[str, Any]:
        r = self._client.get("/api/v1/adapters")
        r.raise_for_status()
        return r.json()

    def trigger_run(
        self, *, agent: str, suite: str | None = None
    ) -> dict[str, Any]:
        payload: dict[str, Any] = {"agent": agent}
        if suite:
            payload["suite"] = suite
        r = self._client.post("/api/v1/run", json=payload)
        r.raise_for_status()
        return r.json()

    def get_run(self, run_id: str) -> dict[str, Any]:
        r = self._client.get(f"/api/v1/run/{run_id}")
        r.raise_for_status()
        return r.json()

    def list_runs(self, agent: str | None = None) -> dict[str, Any]:
        params: dict[str, str] = {}
        if agent:
            params["agent"] = agent
        r = self._client.get("/api/v1/runs", params=params)
        r.raise_for_status()
        return r.json()

    def poll_run(
        self,
        run_id: str,
        *,
        interval: float = 3.0,
        timeout: float = 1800.0,
        on_progress: Any = None,
    ) -> dict[str, Any]:
        """Poll a run until it reaches a terminal state.

        Args:
            run_id:      The run ID returned by ``trigger_run``.
            interval:    Seconds between polls.
            timeout:     Max seconds to wait before giving up.
            on_progress: Optional callback ``(run_data: dict) -> None``.

        Returns:
            The final run state dict.
        """
        deadline = time.monotonic() + timeout
        last_progress = ""

        while time.monotonic() < deadline:
            run = self.get_run(run_id)
            status = run.get("status", "")

            progress = run.get("progress", "")
            if progress and progress != last_progress:
                last_progress = progress
                if on_progress:
                    on_progress(run)

            if status in ("completed", "failed"):
                return run

            time.sleep(interval)

        return self.get_run(run_id)
