"""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.acp import AcpClient
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.numa import NUMAClient
from sbn.reality import RealityClient
from sbn.receipts import ReceiptsClient
from sbn.snapchore import SnapChoreClient


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

    Exposes four domain sub-clients via properties:

    * ``acp``           — autonomous compute procurement: budget, leases, invoices
    * ``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
    * ``numa``          — signal relay, hints, forecasts, diagnostics
    * ``receipts``      — receipt queries (convenience alias)

    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.5",
    ) -> 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._acp = AcpClient(self._transport)
        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)
        self._numa = NUMAClient(self._transport)
        self._receipts = ReceiptsClient(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 acp(self) -> AcpClient:
        return self._acp

    @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

    @property
    def numa(self) -> NUMAClient:
        return self._numa

    @property
    def receipts(self) -> ReceiptsClient:
        return self._receipts

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

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

    def __enter__(self) -> SbnClient:
        return self

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