"""Unified SBN client — single entry point for all network operations."""

from __future__ import annotations

from typing import Sequence

from sbn._http import AuthState, HttpTransport, RetryConfig
from sbn.auth import MintedToken, SigningKey
from sbn.blocks import BlocksClient
from sbn.console import ConsoleClient
from sbn.control_plane import ControlPlaneClient
from sbn.gateway import GatewayClient
from sbn.gec import GecClient
from sbn.governance import GovernanceClient
from sbn.lattice import LatticeClient
from sbn.reality import RealityClient
from sbn.snapchore import SnapChoreClient


class SbnClient:
    """Single entry point for the SmartBlocks Network.

    Exposes four domain sub-clients via properties:

    * ``gateway``       — slots, receipts, attestations
    * ``snapchore``     — capture, verify, seal, chain
    * ``console``       — projects, API keys, usage, billing, webhooks
    * ``control_plane`` — tenants, rate plans, validators
    * ``lattice``       — workflow DAGs, step orchestration, graph edges
    * ``reality``       — fact attestation, evidence, scoring, lattice graph
    * ``blocks``        — SmartBlock creation and queries
    * ``gec``           — GEC compute, frontier registry, health
    * ``governance``    — proposal lifecycle: submit, approve, reject, promote

    Example::

        client = SbnClient(base_url="https://api.smartblocks.network")
        client.authenticate_api_key("sbn_live_abc123")
        block = client.snapchore.capture({"event": "signup"})
    """

    def __init__(
        self,
        *,
        base_url: str = "http://localhost:8090",
        tenant_id: str | None = None,
        retry: RetryConfig | None = None,
        timeout: float = 10.0,
        user_agent: str = "sbn-sdk/0.3",
    ) -> None:
        self._auth = AuthState(tenant_id=tenant_id)
        self._transport = HttpTransport(
            base_url=base_url,
            auth=self._auth,
            retry=retry,
            timeout=timeout,
            user_agent=user_agent,
        )
        self._gateway = GatewayClient(self._transport)
        self._snapchore = SnapChoreClient(self._transport)
        self._console = ConsoleClient(self._transport)
        self._control_plane = ControlPlaneClient(self._transport)
        self._lattice = LatticeClient(self._transport)
        self._reality = RealityClient(self._transport)
        self._blocks = BlocksClient(self._transport)
        self._gec = GecClient(self._transport)
        self._governance = GovernanceClient(self._transport)

    # ── Auth methods ───────────────────────────────────────────────────

    def authenticate_api_key(self, api_key: str) -> None:
        """Set API key auth for all subsequent requests."""
        self._auth.api_key = api_key
        self._auth.bearer_token = None
        self._auth.token_provider = None

    def authenticate_bearer(self, token: str) -> None:
        """Set a static bearer token for all subsequent requests."""
        self._auth.bearer_token = token
        self._auth.api_key = None
        self._auth.token_provider = None

    def authenticate_signing_key(
        self,
        signing_key: SigningKey,
        *,
        subject: str = "sbn-sdk",
        scopes: Sequence[str] = ("attest.write",),
        cdna: str = "sdk",
        ttl_seconds: int = 300,
    ) -> None:
        """Use an Ed25519 signing key with auto-refreshing JWT tokens."""
        self._auth.api_key = None
        self._auth.bearer_token = None

        cache: dict[str, MintedToken] = {}

        def _provider() -> str:
            cached = cache.get("t")
            if cached and not cached.expired:
                return cached.token
            fresh = signing_key.issue_token(
                subject=subject,
                scopes=scopes,
                cdna=cdna,
                ttl_seconds=ttl_seconds,
                tenant_id=self._auth.tenant_id,
            )
            cache["t"] = fresh
            return fresh.token

        self._auth.token_provider = _provider

    def set_tenant(self, tenant_id: str | None) -> None:
        """Switch tenant context for multi-tenant operations."""
        self._auth.tenant_id = tenant_id

    # ── Sub-clients ────────────────────────────────────────────────────

    @property
    def gateway(self) -> GatewayClient:
        return self._gateway

    @property
    def snapchore(self) -> SnapChoreClient:
        return self._snapchore

    @property
    def console(self) -> ConsoleClient:
        return self._console

    @property
    def control_plane(self) -> ControlPlaneClient:
        return self._control_plane

    @property
    def lattice(self) -> LatticeClient:
        return self._lattice

    @property
    def reality(self) -> RealityClient:
        return self._reality

    @property
    def blocks(self) -> BlocksClient:
        return self._blocks

    @property
    def gec(self) -> GecClient:
        return self._gec

    @property
    def governance(self) -> GovernanceClient:
        return self._governance

    # ── Lifecycle ──────────────────────────────────────────────────────

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

    def __enter__(self) -> SbnClient:
        return self

    def __exit__(self, exc_type, exc, tb) -> None:
        self.close()
