"""Golden / snapshot tests for AuthZEN request mapping.

These tests pin the exact AuthZEN request shape for known inputs.
A mapping change will fail the snapshot until explicitly updated.
"""

from __future__ import annotations

from aria_agentkit.policy.mapping import map_tool_call


class TestMapToolCall:
    """Golden tests for the mapping function."""

    def test_agent_only_subject(self) -> None:
        """Agent with no user binding or delegation."""
        m = map_tool_call(
            tool_name="web_search",
            arguments={"query": "hello"},
            call_id="call-001",
            agent_id="agent-42",
            metadata={},
            pdp_application="my-app",
        )
        req = m.authzen_request

        assert req.subject.type == "agent"
        assert req.subject.id == "auth:agent:agentmesh:agent-42"
        assert req.subject.properties == {}

    def test_user_bound_agent(self) -> None:
        """Agent bound to a human principal."""
        m = map_tool_call(
            tool_name="file_read",
            arguments={"path": "/data"},
            call_id="call-002",
            agent_id="agent-7",
            metadata={"user_id": "user-bob"},
            pdp_application="my-app",
        )
        req = m.authzen_request

        assert req.subject.id == "auth:agent:agentmesh:agent-7"
        assert req.subject.properties is not None
        assert req.subject.properties["bound_to_user_id"] == "user-bob"

    def test_delegated_agent(self) -> None:
        """Agent with both user binding and delegation."""
        m = map_tool_call(
            tool_name="db_query",
            arguments={"sql": "SELECT 1"},
            call_id="call-003",
            agent_id="agent-99",
            metadata={
                "user_id": "user-alice",
                "delegator": "agent-supervisor",
                "session_id": "sess-abc",
            },
            pdp_application="my-app",
        )
        req = m.authzen_request

        assert req.subject.properties is not None
        assert req.subject.properties["bound_to_user_id"] == "user-alice"
        assert req.subject.properties["delegator"] == "agent-supervisor"
        assert req.context["session_id"] == "sess-abc"

    def test_tool_with_server_context(self) -> None:
        """Tool call with explicit server_name in metadata."""
        m = map_tool_call(
            tool_name="list_files",
            arguments={},
            call_id="call-004",
            agent_id="a1",
            metadata={"server_name": "prod-gateway"},
            pdp_application="my-app",
        )
        req = m.authzen_request

        assert req.resource.type == "mcp_tool"
        assert req.resource.id == "mcp://prod-gateway/list_files"

    def test_tool_without_server_context(self) -> None:
        """Tool call with no server_name defaults to 'local'."""
        m = map_tool_call(
            tool_name="calculator",
            arguments={"expr": "2+2"},
            call_id="call-005",
            agent_id="a1",
            metadata={},
            pdp_application="my-app",
        )
        req = m.authzen_request

        assert req.resource.id == "mcp://local/calculator"

    def test_action_is_always_tool_invoke(self) -> None:
        m = map_tool_call(
            tool_name="anything",
            arguments={},
            call_id="",
            agent_id="a1",
            metadata={},
            pdp_application="my-app",
        )
        assert m.authzen_request.action.name == "tool.invoke"

    def test_operation_ref_id(self) -> None:
        m = map_tool_call(
            tool_name="send_email",
            arguments={},
            call_id="",
            agent_id="a1",
            metadata={},
            pdp_application="my-app",
        )
        assert m.authzen_request.action.properties is not None
        assert m.authzen_request.action.properties["operation_ref_id"] == "op:tool:send_email"

    def test_original_args_hash_deterministic(self) -> None:
        """Same arguments produce the same hash."""
        args = {"b": 2, "a": 1}
        m1 = map_tool_call(
            tool_name="t",
            arguments=args,
            call_id="",
            agent_id="a",
            metadata={},
            pdp_application="app",
        )
        m2 = map_tool_call(
            tool_name="t",
            arguments=args,
            call_id="",
            agent_id="a",
            metadata={},
            pdp_application="app",
        )
        assert m1.original_args_hash == m2.original_args_hash
        assert len(m1.original_args_hash) == 64

    def test_different_args_different_hash(self) -> None:
        m1 = map_tool_call(
            tool_name="t",
            arguments={"x": 1},
            call_id="",
            agent_id="a",
            metadata={},
            pdp_application="app",
        )
        m2 = map_tool_call(
            tool_name="t",
            arguments={"x": 2},
            call_id="",
            agent_id="a",
            metadata={},
            pdp_application="app",
        )
        assert m1.original_args_hash != m2.original_args_hash

    def test_context_includes_pdp_application(self) -> None:
        m = map_tool_call(
            tool_name="t",
            arguments={},
            call_id="c1",
            agent_id="a1",
            metadata={},
            pdp_application="prod-app",
        )
        assert m.authzen_request.context["pdp_application"] == "prod-app"

    def test_call_id_in_context(self) -> None:
        m = map_tool_call(
            tool_name="t",
            arguments={},
            call_id="my-call-id",
            agent_id="a1",
            metadata={},
            pdp_application="app",
        )
        assert m.authzen_request.context["call_id"] == "my-call-id"

    def test_empty_call_id_omitted(self) -> None:
        m = map_tool_call(
            tool_name="t",
            arguments={},
            call_id="",
            agent_id="a1",
            metadata={},
            pdp_application="app",
        )
        assert "call_id" not in m.authzen_request.context

    def test_anonymous_agent(self) -> None:
        m = map_tool_call(
            tool_name="t",
            arguments={},
            call_id="",
            agent_id="",
            metadata={},
            pdp_application="app",
        )
        assert m.authzen_request.subject.id == "auth:agent:agentmesh:anonymous"

    def test_golden_request_shape(self) -> None:
        """Pin the full JSON shape. If this test fails, the mapping changed."""
        m = map_tool_call(
            tool_name="sql_query",
            arguments={"query": "SELECT * FROM users", "limit": 10},
            call_id="call-golden",
            agent_id="agent-golden",
            metadata={
                "server_name": "data-gateway",
                "user_id": "user-123",
                "session_id": "sess-456",
            },
            pdp_application="golden-app",
        )
        req = m.authzen_request
        dumped = req.model_dump()

        assert dumped["subject"]["type"] == "agent"
        assert dumped["subject"]["id"] == "auth:agent:agentmesh:agent-golden"
        assert dumped["subject"]["properties"]["bound_to_user_id"] == "user-123"
        assert dumped["action"]["name"] == "tool.invoke"
        assert dumped["action"]["properties"]["operation_ref_id"] == "op:tool:sql_query"
        assert dumped["resource"]["type"] == "mcp_tool"
        assert dumped["resource"]["id"] == "mcp://data-gateway/sql_query"
        assert dumped["context"]["pdp_application"] == "golden-app"
        assert dumped["context"]["call_id"] == "call-golden"
        assert dumped["context"]["session_id"] == "sess-456"
        assert "original_args_hash" in dumped["context"]
