"""Tenant context model and context-local accessors (Phase 2A).

Provides a TenantContext dataclass that flows through tool calls via
contextvars.  Tools call ``get_current_tenant()`` to read the active
tenant; the TenantMiddleware sets it before each invocation.
"""
from __future__ import annotations

import contextvars
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional

DEFAULT_TENANT_ID = "default"

# Module-level contextvar — async/thread-safe
_current_tenant: contextvars.ContextVar[Optional["TenantContext"]] = (
    contextvars.ContextVar("_current_tenant", default=None)
)


@dataclass(frozen=True)
class TenantContext:
    """Immutable snapshot of the active tenant for the current request."""

    tenant_id: str = DEFAULT_TENANT_ID
    display_name: str = "Default Tenant"
    tier: str = "CE"
    permissions: List[str] = field(default_factory=lambda: ["*"])
    data_dir: Path = field(default_factory=lambda: Path("data/tenants/default"))
    connection_config: Dict[str, Any] = field(default_factory=dict)
    metadata: Dict[str, Any] = field(default_factory=dict)

    # ------------------------------------------------------------------
    # Factory
    # ------------------------------------------------------------------
    @classmethod
    def default(cls) -> TenantContext:
        """Return a context representing the built-in default tenant."""
        return cls()


def get_current_tenant() -> TenantContext:
    """Read the tenant context for the current execution context.

    Returns the default tenant if none has been set (e.g. outside a
    middleware-managed tool call).
    """
    ctx = _current_tenant.get()
    if ctx is None:
        return TenantContext.default()
    return ctx


def set_current_tenant(ctx: TenantContext) -> contextvars.Token:
    """Set the tenant context and return a reset token.

    Callers (typically middleware) should reset after the tool call::

        token = set_current_tenant(ctx)
        try:
            ...
        finally:
            _current_tenant.reset(token)
    """
    return _current_tenant.set(ctx)


def reset_current_tenant(token: contextvars.Token) -> None:
    """Reset the tenant context to its previous value."""
    _current_tenant.reset(token)
