"""Config-driven metadata enrichment after token exchange.

Some OAuth providers do not include all necessary data in their token response.
For example, Atlassian issues an ``access_token`` but the ``cloud_id`` required
to construct API URLs must be fetched via a separate
``GET /oauth/token/accessible-resources`` call.

:class:`MetadataEnrichmentService` automates these follow-up calls based on a
list of :class:`~empowernow_common.oauth.user_flow.config.EnrichmentStep`
objects declared in :attr:`~empowernow_common.oauth.user_flow.config.OAuthFlowConfig.metadata_enrichment`.
"""

from __future__ import annotations

import logging
from typing import Any

import httpx

from empowernow_common.oauth.user_flow.config import EnrichmentStep
from empowernow_common.oauth.user_flow.exceptions import OAuthEnrichmentError

logger = logging.getLogger(__name__)


class MetadataEnrichmentService:
    """Executes config-driven HTTP calls after the OAuth token exchange.

    Each :class:`~empowernow_common.oauth.user_flow.config.EnrichmentStep` in
    the list is executed sequentially.  Results are injected into *token_data*
    under the key specified by :attr:`~empowernow_common.oauth.user_flow.config.EnrichmentStep.inject_into`.

    Failure policy:

    +---------------------+--------------------------------------------------+
    | ``required=False``  | Log a warning and continue — token_data is       |
    | (default)           | unchanged for that key.                          |
    +---------------------+--------------------------------------------------+
    | ``required=True``   | Raise :class:`~empowernow_common.oauth.user_flow.exceptions.OAuthEnrichmentError`; |
    |                     | no credential is stored.                         |
    +---------------------+--------------------------------------------------+

    Example::

        service = MetadataEnrichmentService(http_client)
        token_data = await service.enrich(token_data, config.metadata_enrichment)
        # token_data["resources"] now contains the Atlassian accessible-resources response
    """

    def __init__(self, http_client: httpx.AsyncClient) -> None:
        self._http = http_client

    async def enrich(
        self,
        token_data: dict[str, Any],
        steps: list[EnrichmentStep],
    ) -> dict[str, Any]:
        """Execute enrichment steps sequentially, injecting results into *token_data*.

        Args:
            token_data: Token response from the provider.  Mutated in place.
            steps:      Ordered list of enrichment API calls to execute.

        Returns:
            The enriched ``token_data`` dict (same object, mutated in place).

        Raises:
            OAuthEnrichmentError: If a step with ``required=True`` fails.
        """
        for step in steps:
            try:
                headers = self._build_auth_headers(step, token_data)
                response = await self._http.request(
                    method=step.method,
                    url=step.url,
                    headers=headers,
                    timeout=10.0,
                )
                response.raise_for_status()
                token_data[step.inject_into] = response.json()

                logger.info(
                    "Metadata enrichment successful",
                    extra={"url": step.url, "inject_into": step.inject_into},
                )

            except Exception as exc:
                if step.required:
                    raise OAuthEnrichmentError(
                        url=step.url,
                        reason=str(exc),
                    ) from exc
                logger.warning(
                    "Metadata enrichment failed (non-fatal)",
                    extra={"url": step.url, "error": str(exc)},
                )

        return token_data

    # ------------------------------------------------------------------
    # Internal helpers
    # ------------------------------------------------------------------

    @staticmethod
    def _build_auth_headers(
        step: EnrichmentStep, token_data: dict[str, Any]
    ) -> dict[str, str]:
        """Build the Authorization header for an enrichment request.

        Args:
            step:       The enrichment step configuration.
            token_data: Token response dict (used to extract ``access_token``).

        Returns:
            A headers dict — ``{"Authorization": "Bearer <token>"}`` when
            ``step.auth == "bearer"``, or ``{}`` for ``"none"``.
        """
        if step.auth == "bearer":
            access_token = token_data.get("access_token", "")
            return {"Authorization": f"Bearer {access_token}"}
        return {}
