"""Mithril API client.

Provides a high-level interface for interacting with the Mithril API.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import httpx

from mithril.api.bindings import AuthenticatedClient
from mithril.api.bindings.api.volumes import get_volumes_v2_volumes_get
from mithril.api.bindings.models import HTTPValidationError
from mithril.config import load_config

if TYPE_CHECKING:
    from mithril.api.bindings.models import VolumeModel
    from mithril.config import Config

DEFAULT_TIMEOUT = httpx.Timeout(30.0)


class MithrilAPIError(Exception):
    """Raised when the API returns an unexpected or invalid response."""


class MithrilClient:
    """Client for interacting with the Mithril API.

    Can be constructed with explicit credentials or loaded from config:

        # Load from environment/config file
        client = MithrilClient()

        # Explicit credentials
        client = MithrilClient(api_url="https://api.mithril.ai", api_key="...")

        # From existing config
        client = MithrilClient.from_config(config)
    """

    def __init__(
        self,
        api_url: str | None = None,
        api_key: str | None = None,
        *,
        project_id: str | None = None,
        timeout: httpx.Timeout | None = None,
    ) -> None:
        """Initialize the client.

        Args:
            api_url: Base URL of the API. If not provided, loaded from config.
            api_key: API key for authentication. If not provided, loaded from config.
            project_id: Default project ID. If not provided, loaded from config.
            timeout: Request timeout configuration.

        Raises:
            ConfigError: If credentials not provided and config is missing/invalid.
        """
        if api_url is not None and api_key is not None:
            self._api_url = api_url
            self._api_key = api_key
            self._project_id = project_id or ""
        else:
            config = load_config()
            self._api_url = api_url or config.api_url
            self._api_key = api_key or config.api_key
            self._project_id = project_id or config.project_id

        self._timeout = timeout or DEFAULT_TIMEOUT
        self._http_client: AuthenticatedClient | None = None

    @classmethod
    def from_config(cls, config: Config) -> MithrilClient:
        """Create a client from an existing Config object.

        Args:
            config: Configuration object with API credentials.

        Returns:
            Configured MithrilClient instance.
        """
        return cls(
            api_url=config.api_url,
            api_key=config.api_key,
            project_id=config.project_id,
        )

    @property
    def project_id(self) -> str:
        """The default project ID for this client."""
        return self._project_id

    @property
    def _client(self) -> AuthenticatedClient:
        """Lazily create the underlying HTTP client."""
        if self._http_client is None:
            self._http_client = AuthenticatedClient(
                base_url=self._api_url,
                token=self._api_key,
                timeout=self._timeout,
            )
        return self._http_client

    def list_volumes(
        self,
        project_id: str | None = None,
        *,
        region: str | None = None,
    ) -> list[VolumeModel]:
        """List volumes for a project.

        Args:
            project_id: Project to list volumes for. Defaults to client's project_id.
            region: Optional region filter.

        Returns:
            List of VolumeModel objects.

        Raises:
            MithrilAPIError: If the API returns a validation error or
                unexpected response.
        """
        project = project_id or self._project_id
        result = get_volumes_v2_volumes_get.sync(
            client=self._client,
            project=project,
            region=region,
        )
        if isinstance(result, list):
            return result
        error_info = (
            result.detail if isinstance(result, HTTPValidationError) else result
        )
        msg = f"Unexpected API response when listing volumes: {error_info}"
        raise MithrilAPIError(msg)
