"""Tests for ARIAPolicyProvider."""

from __future__ import annotations

import httpx
import pytest
from authzen_backend.auth import ClientCredentialsAuth

from aria_agentkit.policy.provider import ARIAPolicyProvider


class TestProviderGetPolicies:
    def test_fetches_and_parses_policies(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        )
        policies = provider.get_policies()
        assert len(policies) == 2
        assert policies[0].policy_id == "pol-001"
        assert policies[0].name == "tool-access"
        assert len(policies[0].rules) == 1

    def test_filters_by_action_type(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        )
        policies = provider.get_policies(action_type="data.read")
        assert len(policies) == 1
        assert policies[0].name == "read-only"

    def test_returns_empty_on_no_match(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        )
        policies = provider.get_policies(action_type="nonexistent.action")
        assert len(policies) == 0


class TestProviderAgentIdFilter:
    def test_filters_by_agent_id_metadata(self) -> None:
        """Policies with metadata.agent_id are filtered; untagged policies pass."""

        def handler(request: httpx.Request) -> httpx.Response:
            return httpx.Response(
                status_code=200,
                json={
                    "policies": [
                        {
                            "id": "p1",
                            "name": "agent-a-only",
                            "description": "",
                            "rules": [],
                            "metadata": {"agent_id": "agent-a"},
                        },
                        {
                            "id": "p2",
                            "name": "agent-b-only",
                            "description": "",
                            "rules": [],
                            "metadata": {"agent_id": "agent-b"},
                        },
                        {
                            "id": "p3",
                            "name": "global",
                            "description": "",
                            "rules": [],
                            "metadata": {},
                        },
                    ]
                },
            )

        client = httpx.Client(transport=httpx.MockTransport(handler))
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=client,
        )
        policies = provider.get_policies(agent_id="agent-a")
        names = [p.name for p in policies]
        assert "agent-a-only" in names
        assert "global" in names
        assert "agent-b-only" not in names


class TestProviderCache:
    def test_caches_policies(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
            cache_ttl=300.0,
        )
        p1 = provider.get_policies()
        p2 = provider.get_policies()
        assert len(p1) == len(p2) == 2

    def test_refresh_invalidates_cache(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        )
        provider.get_policies()
        provider.refresh()
        assert provider._cached_policies == []


class TestProviderMetadata:
    def test_metadata_is_populated(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        )
        meta = provider.metadata
        assert meta.name == "aria-pdp"
        assert meta.plugin_type == "policy_provider"


class TestProviderErrors:
    def test_error_returns_stale_cache(self) -> None:
        call_count = 0

        def handler(request: httpx.Request) -> httpx.Response:
            nonlocal call_count
            call_count += 1
            if call_count == 1:
                return httpx.Response(
                    status_code=200,
                    json={
                        "policies": [{"id": "p1", "name": "n", "description": "d", "rules": []}]
                    },
                )
            return httpx.Response(status_code=500, text="fail")

        client = httpx.Client(transport=httpx.MockTransport(handler))
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=client,
            cache_ttl=0,
        )
        p1 = provider.get_policies()
        assert len(p1) == 1

        p2 = provider.get_policies()
        assert len(p2) == 1

    def test_both_auth_raises(self) -> None:
        with pytest.raises(ValueError, match="not both"):
            ARIAPolicyProvider(
                pdp_base_url="http://localhost:8001",
                pdp_application="test-app",
                token="tok",
                client_credentials=ClientCredentialsAuth(
                    token_endpoint="http://idp/token",
                    client_id="cid",
                    client_secret="csec",
                ),
            )


class TestProviderContextManager:
    def test_context_manager(self, mock_pdp_policies: httpx.Client) -> None:
        with ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        ) as provider:
            policies = provider.get_policies()
            assert len(policies) == 2


class TestProviderRepr:
    def test_repr_contains_url_and_app(self, mock_pdp_policies: httpx.Client) -> None:
        provider = ARIAPolicyProvider(
            pdp_base_url="http://localhost:8001",
            pdp_application="test-app",
            http_client=mock_pdp_policies,
        )
        r = repr(provider)
        assert "ARIAPolicyProvider" in r
        assert "http://localhost:8001" in r
        assert "test-app" in r
