"""BuildAI SDK client."""

from __future__ import annotations

from typing import Any

from ._http import HttpTransport
from .errors import ConfigError
from .resources.v1 import (
    AccessResource,
    AnalyzeResource,
    AssetsResource,
    ClipsResource,
    DatasetsResource,
    EmbeddingsResource,
    FactoriesResource,
    FramesResource,
    JobsResource,
    KeysResource,
    OperationsResource,
    PartnersResource,
    PredictionsResource,
    QueryResource,
    SchemaResource,
    SearchResource,
    SessionsResource,
    StatsResource,
    StreamsResource,
    WorkersResource,
)


class _InternalGuard:
    """Descriptor that raises ConfigError when accessed in public mode."""

    def __init__(self, resource_name: str) -> None:
        self._attr = f"_internal_{resource_name}"
        self._name = resource_name

    def __set_name__(self, owner: type, name: str) -> None:
        self._attr = f"_internal_{name}"
        self._name = name

    def __get__(self, obj: Any, objtype: type | None = None) -> Any:
        if obj is None:
            return self
        if obj._mode != "internal":
            raise ConfigError(
                f"'{self._name}' requires mode='internal'. "
                f"Create the client with: Client(mode='internal')"
            )
        return getattr(obj, self._attr)


class Client:
    """BuildAI SDK client.

    Usage::

        import buildai

        client = buildai.Client(api_key="bai_...")

        hits = client.search("person welding")
        for h in hits.data:
            print(h.clip_id, h.score)

        clip = client.clips.get("clip-uuid")

    Internal mode (requires an internal credential)::

        client = buildai.Client(api_key="bai_...", mode="internal")
        jobs = list(client.jobs.iter(status="running"))
    """

    # Internal-mode-only resources
    access = _InternalGuard("access")
    keys = _InternalGuard("keys")
    operations = _InternalGuard("operations")
    partners = _InternalGuard("partners")
    schema = _InternalGuard("schema")
    query = _InternalGuard("query")

    def __init__(
        self,
        api_key: str | None = None,
        *,
        base_url: str | None = None,
        timeout: float | None = None,
        max_retries: int = 3,
        mode: str = "public",  # "public" | "internal"
        retry_on_mutation: bool = False,
    ) -> None:
        if mode not in {"public", "internal"}:
            raise ValueError("mode must be 'public' or 'internal'")
        self._mode = mode
        self._http = HttpTransport(
            api_key=api_key,
            base_url=base_url,
            timeout=timeout,
            max_retries=max_retries,
            mode=mode,  # type: ignore[arg-type]
            retry_on_mutation=retry_on_mutation,
        )

        # Public resources — always available
        self.search = SearchResource(self._http)
        self.embeddings = EmbeddingsResource(self._http)
        self.datasets = DatasetsResource(self._http)
        self.factories = FactoriesResource(self._http)
        self.workers = WorkersResource(self._http)
        self.clips = ClipsResource(self._http)
        self.analyze = AnalyzeResource(self._http)
        self.jobs = JobsResource(self._http)
        self.stats = StatsResource(self._http)
        self.assets = AssetsResource(self._http)
        self.sessions = SessionsResource(self._http)
        self.streams = StreamsResource(self._http)
        self.frames = FramesResource(self._http)
        self.predictions = PredictionsResource(self._http)

        # Internal-only resources — gated by _InternalGuard descriptor
        self._internal_access = AccessResource(self._http)
        self._internal_keys = KeysResource(self._http)
        self._internal_operations = OperationsResource(self._http)
        self._internal_partners = PartnersResource(self._http)
        self._internal_schema = SchemaResource(self._http)
        self._internal_query = QueryResource(self._http)

    def close(self) -> None:
        self._http.close()

    def __enter__(self) -> Client:
        return self

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

    def __repr__(self) -> str:
        return f"Client(base_url={self._http.base_url!r}, mode={self._mode!r})"
