"""GCP integration hooks -- optional, requires the `gcp` extra
(`pip install a2a-passport[gcp]`).

GCP doesn't run a general-purpose OAuth2 client-credentials IdP for
workloads the way Cognito or Entra ID do. Its idiomatic service-to-service
pattern is different: a workload already has an identity (a GCE/Cloud
Run/GKE service account, resolved via Application Default Credentials), and
it mints a short-lived, Google-signed ID token scoped to whoever it's
calling, with no separate client secret involved at all.

This module provides both ends of that pattern:

- google_id_token_provider(): a TokenProvider that mints a Google ID token
  for a target audience via ADC -- lets a GCP-hosted agent call OUT to an
  AWS- or Azure-hosted agent using its own native GCP identity.
- google_id_token_verifier(): a JWKSVerifier pre-wired to Google's public
  certs -- lets an AWS- or Azure-hosted agent accept calls FROM a GCP agent
  without needing to know anything about GCP beyond "verify against
  Google's JWKS".
- secret_from_gcp_secret_manager(): mirrors the AWS/Azure secret helpers,
  for a GCP-hosted agent that needs to pull a client secret (e.g. to call
  OUT to Cognito or Entra ID as a registered OAuth2 client instead).

Together with a2a_passport.integrations.aws and .azure, this closes the
federation triangle: any of AWS, Azure, or GCP can be the caller or the
callee, verified by whichever side received the request, with no shared
custom IdP required.
"""
from __future__ import annotations

import asyncio
import time

import jwt

from a2a_passport.auth.verifiers import JWKSVerifier

GOOGLE_JWKS_URI = "https://www.googleapis.com/oauth2/v3/certs"
GOOGLE_ISSUER = "https://accounts.google.com"


def google_id_token_verifier() -> JWKSVerifier:
    """JWKSVerifier pre-configured for Google-signed ID tokens.

    Works for tokens minted by google_id_token_provider() below, whether
    the underlying identity is a GCE/Cloud Run/GKE service account or a
    user's Google account -- Google publishes one public JWKS for all of
    them at a fixed, well-known URL.
    """
    return JWKSVerifier(jwks_uri=GOOGLE_JWKS_URI, issuer=GOOGLE_ISSUER)


class GoogleIDTokenProvider:
    """Mints Google-signed ID tokens for a target audience via Application
    Default Credentials -- no client secret involved.

    On GCE/Cloud Run/GKE with a workload identity attached, this resolves
    automatically from the metadata server. Locally, it falls back to
    `gcloud auth application-default login` credentials or a service
    account key file pointed to by GOOGLE_APPLICATION_CREDENTIALS.

    Caches per audience like a2a_passport's other TokenProviders, refreshing
    shortly before the token's own `exp` claim.
    """

    def __init__(self, *, cache_leeway_seconds: int = 60):
        self._leeway = cache_leeway_seconds
        self._cache: dict[str, tuple[str, float]] = {}

    async def get_token(self, audience: str) -> str:
        cached = self._cache.get(audience)
        now = time.time()
        if cached and cached[1] > now:
            return cached[0]

        token = await asyncio.to_thread(self._fetch, audience)
        claims = jwt.decode(token, options={"verify_signature": False})
        expiry = claims.get("exp", now + 3600) - self._leeway
        self._cache[audience] = (token, expiry)
        return token

    def _fetch(self, audience: str) -> str:
        import google.auth.transport.requests
        import google.oauth2.id_token

        request = google.auth.transport.requests.Request()
        return google.oauth2.id_token.fetch_id_token(request, audience)


def secret_from_gcp_secret_manager(
    secret_id: str, *, project_id: str | None = None, version: str = "latest"
) -> str:
    """Fetch a secret value from GCP Secret Manager.

    Uses Application Default Credentials -- an attached service account is
    the common case when running on GCP; no credentials need to be passed
    here explicitly. `secret_id` may be a short name (with `project_id`
    supplied separately) or a full resource path
    (`projects/{project}/secrets/{name}/versions/{version}`).
    """
    from google.cloud import secretmanager

    client = secretmanager.SecretManagerServiceClient()
    resource_name = (
        secret_id
        if secret_id.startswith("projects/")
        else f"projects/{project_id}/secrets/{secret_id}/versions/{version}"
    )
    response = client.access_secret_version(name=resource_name)
    return response.payload.data.decode("utf-8")
