"""ConvexityClient and AsyncConvexityClient implementations."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from convexity_api_client import AuthenticatedClient
from convexity_api_client import Client as ApiClient
import httpx

from .config import SDKConfig, resolve_config
from .http import AsyncTransport, SyncTransport

if TYPE_CHECKING:
    from .resources.api_keys import ApiKeys
    from .resources.connections import Connections
    from .resources.dashboards import Dashboards
    from .resources.datalake import Datalake
    from .resources.datasets import Datasets
    from .resources.organizations import Organizations
    from .resources.projects import Projects
    from .resources.runs import Runs
    from .resources.tasks import Tasks


def _build_api_client(config: SDKConfig) -> AuthenticatedClient | ApiClient:
    """Build a generated ``convexity_api_client`` client from SDK config."""
    timeout = httpx.Timeout(config.timeout)
    if config.api_key:
        return AuthenticatedClient(
            base_url=config.base_url,
            token=config.api_key,
            prefix="",  # No prefix – uses X-API-Key header
            auth_header_name="X-API-Key",
            timeout=timeout,
            headers=config.extra_headers,
            raise_on_unexpected_status=True,
            follow_redirects=True,
        )
    return ApiClient(
        base_url=config.base_url,
        timeout=timeout,
        headers=config.extra_headers,
        follow_redirects=True,
    )


class ConvexityClient:
    """Synchronous, high-level Python client for the Convexity platform.

    Usage::

        from convexity_sdk import ConvexityClient

        client = ConvexityClient(api_key="cvx_abc_xxx")
        print(client.base_url)

    The client also works as a context manager::

        with ConvexityClient() as client:
            ...
    """

    def __init__(
        self,
        *,
        api_key: str | None = None,
        base_url: str | None = None,
        timeout: float | None = None,
        max_retries: int | None = None,
        retry_backoff: float | None = None,
        extra_headers: dict[str, str] | None = None,
    ) -> None:
        self._config: SDKConfig = resolve_config(
            api_key=api_key,
            base_url=base_url,
            timeout=timeout,
            max_retries=max_retries,
            retry_backoff=retry_backoff,
            extra_headers=extra_headers,
        )
        self._transport = SyncTransport(self._config)
        self._api_client = _build_api_client(self._config)

    # -- properties -----------------------------------------------------------

    @property
    def base_url(self) -> str:
        """The platform base URL this client is connected to."""
        return self._config.base_url

    @property
    def _http(self) -> SyncTransport:
        """Internal transport – used by resource sub-clients."""
        return self._transport

    # -- resource sub-clients -------------------------------------------------
    # These are added incrementally as resource modules are implemented.
    # Lazy properties avoid import-time cost and circular deps.

    @property
    def organizations(self) -> Organizations:
        """Access organization operations."""
        if not hasattr(self, "_organizations"):
            from .resources.organizations import Organizations

            self._organizations = Organizations(self._api_client)
        return self._organizations

    @property
    def api_keys(self) -> ApiKeys:
        """Access API key operations."""
        if not hasattr(self, "_api_keys"):
            from .resources.api_keys import ApiKeys

            self._api_keys = ApiKeys(self._api_client)
        return self._api_keys

    @property
    def connections(self) -> Connections:
        """Access connection operations."""
        if not hasattr(self, "_connections"):
            from .resources.connections import Connections

            self._connections = Connections(self._api_client)
        return self._connections

    @property
    def datalake(self) -> Datalake:
        """Access datalake operations."""
        if not hasattr(self, "_datalake"):
            from .resources.datalake import Datalake

            self._datalake = Datalake(self._api_client)
        return self._datalake

    @property
    def projects(self) -> Projects:
        """Access project operations."""
        if not hasattr(self, "_projects"):
            from .resources.projects import Projects

            self._projects = Projects(self._api_client)
        return self._projects

    @property
    def datasets(self) -> Datasets:
        """Access dataset operations."""
        if not hasattr(self, "_datasets"):
            from .resources.datasets import Datasets

            self._datasets = Datasets(self._api_client)
        return self._datasets

    @property
    def dashboards(self) -> Dashboards:
        """Access dashboard operations."""
        if not hasattr(self, "_dashboards"):
            from .resources.dashboards import Dashboards

            self._dashboards = Dashboards(self._api_client)
        return self._dashboards

    @property
    def tasks(self) -> Tasks:
        """Access task operations."""
        if not hasattr(self, "_tasks"):
            from .resources.tasks import Tasks

            self._tasks = Tasks(self._api_client)
        return self._tasks

    @property
    def runs(self) -> Runs:
        """Access run operations."""
        if not hasattr(self, "_runs"):
            from .resources.runs import Runs

            self._runs = Runs(self._api_client)
        return self._runs

    # -- context manager ------------------------------------------------------

    def __enter__(self) -> ConvexityClient:
        return self

    def __exit__(self, *args: Any) -> None:
        self.close()

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

    # -- repr -----------------------------------------------------------------

    def __repr__(self) -> str:
        return f"ConvexityClient(base_url={self.base_url!r})"


class AsyncConvexityClient:
    """Asynchronous, high-level Python client for the Convexity platform.

    Usage::

        from convexity_sdk import AsyncConvexityClient

        async with AsyncConvexityClient() as client:
            ...
    """

    def __init__(
        self,
        *,
        api_key: str | None = None,
        base_url: str | None = None,
        timeout: float | None = None,
        max_retries: int | None = None,
        retry_backoff: float | None = None,
        extra_headers: dict[str, str] | None = None,
    ) -> None:
        self._config: SDKConfig = resolve_config(
            api_key=api_key,
            base_url=base_url,
            timeout=timeout,
            max_retries=max_retries,
            retry_backoff=retry_backoff,
            extra_headers=extra_headers,
        )
        self._transport = AsyncTransport(self._config)

    # -- properties -----------------------------------------------------------

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

    @property
    def _http(self) -> AsyncTransport:
        return self._transport

    # -- context manager ------------------------------------------------------

    async def __aenter__(self) -> AsyncConvexityClient:
        return self

    async def __aexit__(self, *args: Any) -> None:
        await self.close()

    async def close(self) -> None:
        await self._transport.close()

    def __repr__(self) -> str:
        return f"AsyncConvexityClient(base_url={self.base_url!r})"
