"""Base GA4GH client that all spec plugins extend."""

from __future__ import annotations

from typing import Any

from ai4gh.core.auth import AuthHandler, auto_detect_auth
from ai4gh.core.config import Config
from ai4gh.core.transport import Transport
from ai4gh.core.types import ServiceInfo


class GA4GHClient:
    """Base client for GA4GH API specifications.

    All spec-specific clients inherit from this class, which provides:
    - HTTP transport with retry and rate limiting
    - Authentication handling
    - Service Info retrieval
    - Consistent URL construction
    """

    spec_name: str = ""
    spec_version: str = ""
    base_path: str = ""

    def __init__(
        self,
        base_url: str | None = None,
        *,
        auth: AuthHandler | None = None,
        config: Config | None = None,
        transport: Transport | None = None,
    ) -> None:
        self._config = config or Config()
        self._base_url = (base_url or self._config.get_spec_url(self.spec_name) or "").rstrip("/")
        self._auth = auth or auto_detect_auth(self._config.auth)
        self._transport = transport or Transport(self._config)

    @property
    def url(self) -> str:
        """Full base URL including the spec's base path."""
        return f"{self._base_url}{self.base_path}"

    async def _get_auth_headers(self) -> dict[str, str]:
        """Get authentication headers."""
        return await self._auth.get_headers()

    async def _request(
        self,
        method: str,
        path: str,
        *,
        params: dict[str, Any] | None = None,
        json: Any = None,
        headers: dict[str, str] | None = None,
    ) -> Any:
        """Make an authenticated request to the GA4GH API.

        Args:
            method: HTTP method (GET, POST, etc.)
            path: Path relative to the spec's base URL.
            params: Query parameters.
            json: JSON body for POST/PUT.
            headers: Additional headers.

        Returns:
            Parsed JSON response.
        """
        url = f"{self.url}{path}"
        auth_headers = await self._get_auth_headers()

        merged_headers = {**auth_headers}
        if headers:
            merged_headers.update(headers)

        if method.upper() == "GET":
            response = await self._transport.get(url, headers=merged_headers, params=params)
        elif method.upper() == "POST":
            response = await self._transport.post(
                url, headers=merged_headers, params=params, json=json
            )
        elif method.upper() == "DELETE":
            response = await self._transport.delete(url, headers=merged_headers)
        else:
            response = await self._transport.get(url, headers=merged_headers)

        return response.json()

    async def get_service_info(self) -> ServiceInfo:
        """Get the service info for this GA4GH endpoint.

        Returns:
            ServiceInfo model with service metadata.
        """
        data = await self._request("GET", "/service-info")
        return ServiceInfo.model_validate(data)

    async def close(self) -> None:
        """Close the underlying HTTP transport."""
        await self._transport.close()

    async def __aenter__(self) -> GA4GHClient:
        """Async context manager entry."""
        return self

    async def __aexit__(self, *args: Any) -> None:
        """Async context manager exit."""
        await self.close()
