"""TowerClient — unified entry point for the Tower Agent Profile SDK.

Mirrors the SbnClient pattern: single constructor, profile-scoped
sub-clients via properties, shared auth and transport.

Usage::

    from tower import TowerClient

    # Connect to Tower Agent API
    client = TowerClient(
        base_url="http://localhost:8001",
        api_key="sk-tower-...",
        project_id="proj-001",
    )

    # Mint a Dominion agent profile
    agent = client.dominion.create(
        employee_id="emp-42",
        project_id="proj-001",
        role="payroll_operator",
        department="Finance",
    )
    agent_id = agent["agent_id"]

    # Feed payroll context
    client.dominion.ingest_batch(agent_id, batch_summary={...})
    client.dominion.ingest_float(agent_id, float_health={...})

    # Trigger a tick — agent processes context and returns suggestions
    result = client.dominion.tick(agent_id)

    # Get suggestions and submit feedback
    suggestions = client.dominion.suggestions(agent_id)
    client.dominion.feedback(agent_id, "sug-001", feedback_type="accept")

    # Get operator brief
    brief = client.dominion.operator_brief(agent_id)

    # Scores and reviews
    scores = client.dominion.scores(agent_id)

    # Lifecycle
    client.dominion.suspend(agent_id, reason="employee_leave")
    client.dominion.resume(agent_id)

    # Clean up
    client.close()
"""

from __future__ import annotations

from typing import Any, Callable, Dict, List, Sequence

from tower._http import AuthState, HttpTransport, RetryConfig
from tower.profiles.dominion import DominionProfileClient
from tower.profiles.grid import GridProfileClient
from tower.profiles.stillpoint import StillpointProfileClient
from tower.profiles._base import BaseProfileClient


class TowerClient:
    """Single entry point for the Tower Agent Profile SDK.

    Exposes three profile-scoped sub-clients:

    * ``dominion``    — payroll-scoped agent operations
    * ``grid``        — multi-product Grid operator operations
    * ``stillpoint``  — treasury-scoped agent operations

    Plus shared operations (create_agent, suggestions, feedback, scores)
    available on any profile client or directly on TowerClient for
    profile-agnostic usage.

    Example::

        client = TowerClient(base_url="http://localhost:8001")
        client.authenticate_api_key("sk-tower-abc123")

        # Profile-specific
        client.dominion.ingest_batch(agent_id, summary)

        # Profile-agnostic (use the base client)
        client.agents.suggestions(agent_id)
    """

    def __init__(
        self,
        *,
        base_url: str = "http://localhost:8001",
        api_key: str | None = None,
        project_id: str | None = None,
        retry: RetryConfig | None = None,
        timeout: float = 10.0,
        user_agent: str = "tower-sdk/0.1",
    ) -> None:
        self._auth = AuthState(
            api_key=api_key,
            project_id=project_id,
        )
        self._transport = HttpTransport(
            base_url=base_url,
            auth=self._auth,
            retry=retry,
            timeout=timeout,
            user_agent=user_agent,
        )

        # Profile sub-clients
        self._dominion = DominionProfileClient(self._transport)
        self._grid = GridProfileClient(self._transport)
        self._stillpoint = StillpointProfileClient(self._transport)
        self._agents = BaseProfileClient(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_token_provider(self, provider: Callable[[], str]) -> None:
        """Set a dynamic token provider (e.g. auto-refreshing JWT)."""
        self._auth.token_provider = provider
        self._auth.api_key = None
        self._auth.bearer_token = None

    def set_project(self, project_id: str | None) -> None:
        """Switch project context for multi-project operations."""
        self._auth.project_id = project_id

    # ── Profile sub-clients ───────────────────────────────────────────

    @property
    def dominion(self) -> DominionProfileClient:
        """Payroll-scoped agent profile operations."""
        return self._dominion

    @property
    def grid(self) -> GridProfileClient:
        """Grid operator agent profile operations."""
        return self._grid

    @property
    def stillpoint(self) -> StillpointProfileClient:
        """Treasury-scoped agent profile operations."""
        return self._stillpoint

    @property
    def agents(self) -> BaseProfileClient:
        """Profile-agnostic agent operations (CRUD, suggestions, feedback, scores)."""
        return self._agents

    # ── Convenience shortcuts (delegate to base client) ───────────────

    def create_agent(
        self,
        *,
        employee_id: str,
        project_id: str,
        profile: str = "",
        role: str = "standard",
        department: str = "",
        config: Dict[str, Any] | None = None,
    ) -> Dict[str, Any]:
        """Create an agent (any profile). Shortcut for ``client.agents.create(...)``."""
        client = self._resolve_profile(profile)
        return client.create(
            employee_id=employee_id,
            project_id=project_id,
            role=role,
            department=department,
            config=config,
        )

    def get_agent(self, agent_id: str) -> Dict[str, Any]:
        """Get agent status. Shortcut for ``client.agents.get(...)``."""
        return self._agents.get(agent_id)

    def suggestions(
        self,
        agent_id: str,
        **kwargs: Any,
    ) -> List[Dict[str, Any]]:
        """List suggestions. Shortcut for ``client.agents.suggestions(...)``."""
        return self._agents.suggestions(agent_id, **kwargs)

    def feedback(
        self,
        agent_id: str,
        suggestion_id: str,
        *,
        feedback_type: str,
        **kwargs: Any,
    ) -> Dict[str, Any]:
        """Submit feedback. Shortcut for ``client.agents.feedback(...)``."""
        return self._agents.feedback(
            agent_id, suggestion_id, feedback_type=feedback_type, **kwargs,
        )

    def scores(self, agent_id: str) -> Dict[str, Any]:
        """Get scores. Shortcut for ``client.agents.scores(...)``."""
        return self._agents.scores(agent_id)

    def suspend(self, agent_id: str, *, reason: str = "manual") -> Dict[str, Any]:
        """Suspend agent. Shortcut for ``client.agents.suspend(...)``."""
        return self._agents.suspend(agent_id, reason=reason)

    def resume(self, agent_id: str) -> Dict[str, Any]:
        """Resume agent. Shortcut for ``client.agents.resume(...)``."""
        return self._agents.resume(agent_id)

    # ── Internals ─────────────────────────────────────────────────────

    def _resolve_profile(self, profile: str) -> BaseProfileClient:
        """Resolve a profile name to the appropriate sub-client."""
        if profile == "dominion":
            return self._dominion
        elif profile == "grid_operator":
            return self._grid
        elif profile == "stillpoint":
            return self._stillpoint
        return self._agents

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

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

    def __enter__(self) -> TowerClient:
        return self

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