"""Tests for the PyAuthz Strawberry GraphQL integration."""

import strawberry
from strawberry.test import BaseGraphQLTestClient

from pyauthz import (
    PyAuthz,
    Role,
    Subject,
)
from pyauthz_strawberry import PyAuthzExtension, get_pyauthz, get_subject, requires


def make_schema(rp: PyAuthz, subject: Subject | None = None):
    """Create a test Strawberry schema with PyAuthz configured."""

    def resolve_user(context: dict) -> Subject:
        if subject is not None:
            return subject
        request = context.get("request")
        if request:
            user_id = request.headers.get("X-User-Id", "anonymous")
            roles_header = request.headers.get("X-User-Roles", "")
            roles = roles_header.split(",") if roles_header else []
            return Subject(id=user_id, roles=roles)
        return Subject(id="anonymous", roles=[])

    @strawberry.type
    class Query:
        @strawberry.field
        def hello(self) -> str:
            return "world"

        @strawberry.field
        @requires("documents:read")
        def documents(self, info: strawberry.types.Info) -> str:
            return "secret docs"

        @strawberry.field
        def current_user(self, info: strawberry.types.Info) -> str:
            sub = get_subject(info.context)
            return sub.id

        @strawberry.field
        def has_pyauthz(self, info: strawberry.types.Info) -> bool:
            rp_instance = get_pyauthz(info.context)
            return rp_instance is not None

    @strawberry.type
    class Mutation:
        @strawberry.mutation
        @requires("documents:delete")
        def delete_document(self, info: strawberry.types.Info, doc_id: str) -> bool:
            return True

    extension = PyAuthzExtension(pyauthz=rp, subject_resolver=resolve_user)
    schema = strawberry.Schema(query=Query, mutation=Mutation, extensions=[extension])
    return schema


class StrawberryTestClient(BaseGraphQLTestClient):
    def request(self, body, headers=None, files=None):
        resp = self._client.post(
            "/graphql",
            json=body,
            headers=headers,
        )
        return resp


class TestStrawberryExtension:
    def test_allowed_query(self):
        rp = PyAuthz()
        rp.add_role(Role(name="admin", permissions=["*:*"]))
        admin = Subject(id="alice", roles=["admin"])
        schema = make_schema(rp, admin)

        result = schema.execute_sync("{ documents }", context_value={})
        assert result.errors is None
        assert result.data["documents"] == "secret docs"

    def test_denied_query(self):
        rp = PyAuthz()
        rp.add_role(Role(name="viewer", permissions=["documents:read"]))
        viewer = Subject(id="bob", roles=[])
        schema = make_schema(rp, viewer)

        result = schema.execute_sync("{ documents }", context_value={})
        assert result.errors is not None
        assert len(result.errors) > 0

    def test_get_subject_helper(self):
        rp = PyAuthz()
        admin = Subject(id="alice", roles=["admin"])
        schema = make_schema(rp, admin)

        result = schema.execute_sync("{ currentUser }", context_value={})
        assert result.errors is None
        assert result.data["currentUser"] == "alice"

    def test_get_pyauthz_helper(self):
        rp = PyAuthz()
        admin = Subject(id="alice", roles=[])
        schema = make_schema(rp, admin)

        result = schema.execute_sync("{ hasPyauthz }", context_value={})
        assert result.errors is None
        assert result.data["hasPyauthz"] is True

    def test_mutation_denied(self):
        rp = PyAuthz()
        rp.add_role(Role(name="viewer", permissions=["documents:read"]))
        viewer = Subject(id="bob", roles=["viewer"])
        schema = make_schema(rp, viewer)

        result = schema.execute_sync(
            'mutation { deleteDocument(docId: "doc-1") }', context_value={}
        )
        assert result.errors is not None

    def test_mutation_allowed(self):
        rp = PyAuthz()
        rp.add_role(Role(name="admin", permissions=["*:*"]))
        admin = Subject(id="alice", roles=["admin"])
        schema = make_schema(rp, admin)

        result = schema.execute_sync(
            'mutation { deleteDocument(docId: "doc-1") }', context_value={}
        )
        assert result.errors is None
        assert result.data["deleteDocument"] is True

    def test_unprotected_field_always_works(self):
        rp = PyAuthz()
        nobody = Subject(id="nobody", roles=[])
        schema = make_schema(rp, nobody)

        result = schema.execute_sync("{ hello }", context_value={})
        assert result.errors is None
        assert result.data["hello"] == "world"
