"""
Internal HTTP request helpers shared by all service clients.
Not part of the public API.
"""

from __future__ import annotations

from typing import Any, Callable, Dict, Optional

import requests
import httpx

from .errors import AgentIdPError


def sync_request(
    method: str,
    base_url: str,
    path: str,
    token: str,
    body: Optional[Any] = None,
    params: Optional[Dict[str, Any]] = None,
) -> Any:
    """
    Make a synchronous authenticated JSON request to the AgentIdP API.

    Args:
        method: HTTP method (GET, POST, PATCH, DELETE).
        base_url: AgentIdP base URL.
        path: API path (e.g. ``/api/v1/agents``).
        token: Bearer access token.
        body: Optional request body (serialised as JSON).
        params: Optional query parameters (None values are excluded).

    Returns:
        Parsed JSON response body, or None for 204 responses.

    Raises:
        AgentIdPError: On any API or network failure.
    """
    url = base_url.rstrip("/") + path
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/json",
    }
    filtered_params: Optional[Dict[str, str]] = (
        {k: str(v) for k, v in params.items() if v is not None}
        if params
        else None
    )

    try:
        response = requests.request(
            method=method,
            url=url,
            headers=headers,
            json=body,
            params=filtered_params,
            timeout=30,
        )
    except requests.RequestException as exc:
        raise AgentIdPError.network_error(exc) from exc

    if response.status_code == 204:
        return None

    resp_body = response.json() if response.content else {}
    if not response.ok:
        raise AgentIdPError.from_api_error(resp_body, response.status_code)
    return resp_body


async def async_request(
    method: str,
    base_url: str,
    path: str,
    token: str,
    body: Optional[Any] = None,
    params: Optional[Dict[str, Any]] = None,
) -> Any:
    """
    Make an asynchronous authenticated JSON request to the AgentIdP API.

    Args:
        method: HTTP method (GET, POST, PATCH, DELETE).
        base_url: AgentIdP base URL.
        path: API path.
        token: Bearer access token.
        body: Optional request body (serialised as JSON).
        params: Optional query parameters (None values are excluded).

    Returns:
        Parsed JSON response body, or None for 204 responses.

    Raises:
        AgentIdPError: On any API or network failure.
    """
    url = base_url.rstrip("/") + path
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/json",
    }
    filtered_params: Optional[Dict[str, str]] = (
        {k: str(v) for k, v in params.items() if v is not None}
        if params
        else None
    )

    try:
        async with httpx.AsyncClient(timeout=30) as client:
            response = await client.request(
                method=method,
                url=url,
                headers=headers,
                json=body,
                params=filtered_params,
            )
    except httpx.RequestError as exc:
        raise AgentIdPError.network_error(exc) from exc

    if response.status_code == 204:
        return None

    resp_body = response.json() if response.content else {}
    if not response.is_success:
        raise AgentIdPError.from_api_error(resp_body, response.status_code)
    return resp_body
