import httpx
from typing import Any, Dict, Optional
from opentelemetry import baggage, propagate, context as otel_context
from guardianhub import get_logger

logger = get_logger(__name__)


class SovereignBaseClient:
    """
    Standardized base client that ensures every outgoing request
    carries the Identity, Tenant, and Trace baggage.
    """

    def __init__(self, base_url: str, timeout: int = 10):
        self._base_url = base_url.rstrip('/')
        self._timeout = timeout

    async def _request(self, method: str, path: str, token: Optional[str] = None, **kwargs) -> Any:
        url = f"{self._base_url}{path}"

        # 1. Context Extraction
        current_ctx = otel_context.get_current()

        # Extract baggage values
        tenant_id = baggage.get_baggage("tenant_id", current_ctx)
        user_id = baggage.get_baggage("user_id", current_ctx)
        access_token = baggage.get_baggage("access_token", current_ctx)

        # 2. Header Preparation
        headers = kwargs.get('headers', {})

        # Prioritize explicit token, then baggage token
        auth_token = token or access_token
        if auth_token:
            # Ensure the "Bearer " prefix is handled cleanly
            headers['Authorization'] = auth_token if auth_token.startswith("Bearer ") else f"Bearer {auth_token}"

        if tenant_id:
            headers['X-Tenant-ID'] = str(tenant_id)
            headers['X-Sovereign-Context'] = "active"

        # 3. OpenTelemetry Propagation (Injects traceparent and baggage headers)
        propagate.inject(headers)
        kwargs['headers'] = headers

        # 4. Execution
        async with httpx.AsyncClient(timeout=self._timeout) as client:
            try:
                response = await client.request(method, url, **kwargs)
                response.raise_for_status()
                return response.json()
            except httpx.HTTPStatusError as e:
                logger.error(f"Sovereign Client Error: {method} {path} failed with {e.response.status_code}",
                             extra={"tenant_id": tenant_id, "user_id": user_id})
                raise