"""HTTP client for admin API calls with JWT or API key auth.

This module is intentionally synchronous (uses :mod:`httpx`'s sync
``Client``) so that Typer command callbacks can call it directly without
``asyncio.run`` boilerplate. The client reads credentials from (in
priority order): explicit args, environment variables, or the config
file at ``~/.agentkit/admin_config.yaml``.
"""

from __future__ import annotations

import os
from pathlib import Path
import httpx
import yaml

DEFAULT_SERVER_URL = "http://localhost:8001"
DEFAULT_CONFIG_PATH = Path.home() / ".agentkit" / "admin_config.yaml"
DEFAULT_TIMEOUT = 30.0


class AdminHttpClient:
    """Synchronous HTTP client for admin API calls.

    Authentication is provided via either a JWT ``access_token`` (sent
    as ``Authorization: Bearer <token>``) or an API key (sent as
    ``X-API-Key: <key>``). When neither is supplied, requests are made
    unauthenticated (the server will return 401/403).
    """

    def __init__(
        self,
        server_url: str,
        token: str | None = None,
        api_key: str | None = None,
    ) -> None:
        self._base_url = server_url.rstrip("/")
        self._token = token
        self._api_key = api_key

    # ------------------------------------------------------------------
    # Construction helpers
    # ------------------------------------------------------------------

    @classmethod
    def from_config(
        cls,
        server_url: str | None = None,
        token: str | None = None,
        api_key: str | None = None,
        config_path: Path | str | None = None,
    ) -> AdminHttpClient:
        """Build a client from args, env vars, or config file.

        Priority (highest first):
        1. Explicit kwargs (``server_url``, ``token``, ``api_key``)
        2. Environment variables: ``AGENTKIT_SERVER_URL``,
           ``AGENTKIT_ADMIN_TOKEN``, ``AGENTKIT_ADMIN_API_KEY``
        3. Config file at ``~/.agentkit/admin_config.yaml``
        4. Hard-coded defaults (server URL only)
        """
        path = Path(config_path) if config_path else DEFAULT_CONFIG_PATH
        file_cfg: dict[str, object] = {}
        if path.exists():
            try:
                with path.open(encoding="utf-8") as f:
                    loaded = yaml.safe_load(f)
                if isinstance(loaded, dict):
                    file_cfg = loaded
            except (yaml.YAMLError, OSError):
                # Corrupt or unreadable config — fall back to defaults.
                file_cfg = {}

        resolved_url = (
            server_url
            or os.environ.get("AGENTKIT_SERVER_URL")
            or file_cfg.get("server_url")
            or DEFAULT_SERVER_URL
        )
        resolved_token = token or os.environ.get("AGENTKIT_ADMIN_TOKEN") or file_cfg.get("token")
        resolved_key = (
            api_key or os.environ.get("AGENTKIT_ADMIN_API_KEY") or file_cfg.get("api_key")
        )
        return cls(
            server_url=resolved_url,
            token=resolved_token,
            api_key=resolved_key,
        )

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    def _headers(self) -> dict[str, str]:
        headers = {"Content-Type": "application/json"}
        if self._token:
            headers["Authorization"] = f"Bearer {self._token}"
        elif self._api_key:
            headers["X-API-Key"] = self._api_key
        return headers

    def _request(
        self,
        method: str,
        path: str,
        *,
        params: dict[str, object] | None = None,
        json: dict[str, object] | None = None,
        timeout: float = DEFAULT_TIMEOUT,
    ) -> httpx.Response:
        url = f"{self._base_url}{path}"
        with httpx.Client(timeout=timeout) as client:
            resp = client.request(
                method,
                url,
                params=params,
                json=json,
                headers=self._headers(),
            )
            resp.raise_for_status()
            return resp

    # ------------------------------------------------------------------
    # Public API
    # ------------------------------------------------------------------

    @property
    def base_url(self) -> str:
        return self._base_url

    def get(self, path: str, params: dict[str, object] | None = None) -> object:
        resp = self._request("GET", path, params=params)
        return resp.json()

    def get_text(self, path: str, params: dict[str, object] | None = None) -> str:
        """GET returning response text (for CSV exports)."""
        resp = self._request("GET", path, params=params)
        return resp.text

    def post(self, path: str, json: dict[str, object] | None = None) -> object:
        resp = self._request("POST", path, json=json)
        return resp.json()

    def put(self, path: str, json: dict[str, object] | None = None) -> object:
        resp = self._request("PUT", path, json=json)
        return resp.json()

    def patch(self, path: str, json: dict[str, object] | None = None) -> object:
        resp = self._request("PATCH", path, json=json)
        return resp.json()

    def delete(self, path: str, params: dict[str, object] | None = None) -> object:
        resp = self._request("DELETE", path, params=params)
        return resp.json()

    def login(self, username: str, password: str) -> str:
        """Authenticate with username/password and return an access token.

        Calls ``POST /api/v1/auth/login``. Raises
        :class:`httpx.HTTPStatusError` on non-2xx responses (e.g. 401
        for invalid credentials).
        """
        with httpx.Client(timeout=10.0) as client:
            resp = client.post(
                f"{self._base_url}/api/v1/auth/login",
                json={"username": username, "password": password},
            )
            resp.raise_for_status()
            data = resp.json()
        return data["access_token"]
