"""Unit tests for the GCP integration hooks. No real GCP project or
Application Default Credentials involved -- google-auth/google-cloud calls
are mocked at the boundary."""
from __future__ import annotations

import time
from unittest.mock import MagicMock, patch

import jwt as pyjwt

from a2a_passport.integrations.gcp import (
    GOOGLE_ISSUER,
    GOOGLE_JWKS_URI,
    GoogleIDTokenProvider,
    google_id_token_verifier,
    secret_from_gcp_secret_manager,
)


def _fake_google_id_token(audience: str, exp_delta: int = 3600) -> str:
    now = int(time.time())
    claims = {
        "iss": GOOGLE_ISSUER,
        "aud": audience,
        "sub": "test-sa@project.iam.gserviceaccount.com",
        "iat": now,
        "exp": now + exp_delta,
    }
    return pyjwt.encode(claims, "unused-for-decode-only", algorithm="HS256")


def test_google_id_token_verifier_uses_googles_public_jwks():
    verifier = google_id_token_verifier()
    assert verifier._issuer == GOOGLE_ISSUER
    assert verifier._jwks_client.uri == GOOGLE_JWKS_URI


class TestGoogleIDTokenProvider:
    async def test_fetches_and_returns_token(self):
        token = _fake_google_id_token("aws-hosted-agent")
        with patch(
            "google.oauth2.id_token.fetch_id_token", return_value=token
        ) as mock_fetch, patch("google.auth.transport.requests.Request"):
            provider = GoogleIDTokenProvider()
            result = await provider.get_token("aws-hosted-agent")

        assert result == token
        assert mock_fetch.call_count == 1
        assert mock_fetch.call_args.args[1] == "aws-hosted-agent"

    async def test_caches_token_per_audience(self):
        token = _fake_google_id_token("azure-hosted-agent")
        with patch(
            "google.oauth2.id_token.fetch_id_token", return_value=token
        ) as mock_fetch, patch("google.auth.transport.requests.Request"):
            provider = GoogleIDTokenProvider()
            await provider.get_token("azure-hosted-agent")
            await provider.get_token("azure-hosted-agent")

        assert mock_fetch.call_count == 1

    async def test_separate_cache_per_audience(self):
        with patch(
            "google.oauth2.id_token.fetch_id_token",
            side_effect=lambda req, aud: _fake_google_id_token(aud),
        ) as mock_fetch, patch("google.auth.transport.requests.Request"):
            provider = GoogleIDTokenProvider()
            await provider.get_token("aws-agent")
            await provider.get_token("azure-agent")

        assert mock_fetch.call_count == 2


def test_secret_from_gcp_secret_manager_short_name():
    mock_response = MagicMock()
    mock_response.payload.data = b"my-gcp-secret"
    mock_client_instance = MagicMock()
    mock_client_instance.access_secret_version.return_value = mock_response

    with patch(
        "google.cloud.secretmanager.SecretManagerServiceClient", return_value=mock_client_instance
    ):
        value = secret_from_gcp_secret_manager("my-secret", project_id="my-project")

    assert value == "my-gcp-secret"
    mock_client_instance.access_secret_version.assert_called_once_with(
        name="projects/my-project/secrets/my-secret/versions/latest"
    )


def test_secret_from_gcp_secret_manager_full_resource_path():
    mock_response = MagicMock()
    mock_response.payload.data = b"my-gcp-secret"
    mock_client_instance = MagicMock()
    mock_client_instance.access_secret_version.return_value = mock_response
    full_path = "projects/my-project/secrets/my-secret/versions/3"

    with patch(
        "google.cloud.secretmanager.SecretManagerServiceClient", return_value=mock_client_instance
    ):
        value = secret_from_gcp_secret_manager(full_path)

    assert value == "my-gcp-secret"
    mock_client_instance.access_secret_version.assert_called_once_with(name=full_path)
