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

Two things an agent running on (or talking to) AWS needs:

1. Verifying tokens issued by Amazon Cognito -- cognito_verifier() derives
   the JWKS URI and issuer from your user pool ID and region, so nobody has
   to look up Cognito's URL conventions by hand.
2. Pulling a client secret out of AWS Secrets Manager at startup instead of
   hardcoding it -- secret_from_secrets_manager() does that using boto3's
   default credential chain (env vars, shared config, or an attached
   IAM role), so no AWS credentials need to be passed here explicitly when
   already running inside AWS.
"""
from __future__ import annotations

import json

from a2a_passport.auth.verifiers import JWKSVerifier


def cognito_verifier(*, user_pool_id: str, region: str) -> JWKSVerifier:
    """JWKSVerifier pre-configured for an Amazon Cognito user pool.

    Pair this with a caller that presents a Cognito-issued token -- e.g. an
    AWS-hosted agent calling into a GCP- or Azure-hosted one. Cognito access
    tokens omit the `aud` claim by default; verify the ID token instead, or
    configure your app client to include an audience, if you rely on it.
    """
    issuer = f"https://cognito-idp.{region}.amazonaws.com/{user_pool_id}"
    return JWKSVerifier(jwks_uri=f"{issuer}/.well-known/jwks.json", issuer=issuer)


def secret_from_secrets_manager(
    secret_id: str, *, region: str | None = None, key: str | None = None
) -> str:
    """Fetch a secret value from AWS Secrets Manager.

    Uses boto3's default credential chain -- an IAM role attached to the
    running task/instance/Lambda is the common case; no credentials need to
    be passed here explicitly. Pass `key` if the secret is stored as a JSON
    blob (e.g. {"client_secret": "..."}) and you want one field out of it.
    """
    import boto3

    client = boto3.client("secretsmanager", region_name=region)
    resp = client.get_secret_value(SecretId=secret_id)
    value = resp.get("SecretString")
    if value is None:
        raise RuntimeError(
            f"secret {secret_id!r} has no SecretString (binary secrets aren't supported)"
        )
    if key is None:
        return value
    return json.loads(value)[key]
