import attr
from django.test import TestCase
from drf_spectacular.generators import SchemaGenerator
from drf_spectacular.utils import extend_schema
from rest_framework.response import Response
from rest_framework.test import APIRequestFactory

from mantle_drf.generics import GenericAPIView, RetrieveAPIView
import mantle_drf.schema  # noqa: F401 — registers the extension
from tests.models import Item


@attr.define
class ItemShape:
    name: str
    slug: str


factory = APIRequestFactory()


class TestAttrsExtension(TestCase):
    def _generate_schema(self, urlpatterns):
        generator = SchemaGenerator(patterns=urlpatterns)
        return generator.get_schema(public=True)

    def test_extend_schema_with_attrs_response(self):
        """attrs class used as response generates correct OpenAPI schema."""
        from django.urls import path

        class TestView(RetrieveAPIView):
            queryset = Item.objects.all()
            shape_class = ItemShape

            @extend_schema(responses=ItemShape)
            def get(self, request, *args, **kwargs):
                return super().get(request, *args, **kwargs)

        urlpatterns = [path("items/<int:pk>/", TestView.as_view())]
        schema = self._generate_schema(urlpatterns)

        item_schema = schema["components"]["schemas"]["ItemShape"]
        assert item_schema["type"] == "object"
        assert "name" in item_schema["properties"]
        assert "slug" in item_schema["properties"]
        assert item_schema["properties"]["name"]["type"] == "string"

    def test_extend_schema_with_attrs_request(self):
        """attrs class used as request generates correct OpenAPI schema."""
        from django.urls import path

        class TestView(GenericAPIView):
            queryset = Item.objects.all()
            shape_class = ItemShape

            @extend_schema(request=ItemShape, responses=ItemShape)
            def post(self, request, *args, **kwargs):
                return Response({})

        urlpatterns = [path("items/", TestView.as_view())]
        schema = self._generate_schema(urlpatterns)

        # The request body should reference the ItemShape component.
        post_op = schema["paths"]["/items/"]["post"]
        request_body = post_op["requestBody"]
        ref = request_body["content"]["application/json"]["schema"]["$ref"]
        assert "ItemShape" in ref

    def test_schema_required_fields(self):
        """Required fields (no default) appear in 'required' list."""
        from django.urls import path

        class TestView(RetrieveAPIView):
            queryset = Item.objects.all()
            shape_class = ItemShape

            @extend_schema(responses=ItemShape)
            def get(self, request, *args, **kwargs):
                return super().get(request, *args, **kwargs)

        urlpatterns = [path("items/<int:pk>/", TestView.as_view())]
        schema = self._generate_schema(urlpatterns)

        item_schema = schema["components"]["schemas"]["ItemShape"]
        assert "name" in item_schema["required"]
        assert "slug" in item_schema["required"]

    def test_schema_optional_field(self):
        """Optional fields are handled correctly."""
        from typing import Optional
        from django.urls import path

        @attr.define
        class OptionalShape:
            name: str
            label: Optional[str] = None

        class TestView(GenericAPIView):
            queryset = Item.objects.all()
            shape_class = OptionalShape

            @extend_schema(responses=OptionalShape)
            def get(self, request, *args, **kwargs):
                return Response({})

        urlpatterns = [path("items/<int:pk>/", TestView.as_view())]
        schema = self._generate_schema(urlpatterns)

        opt_schema = schema["components"]["schemas"]["OptionalShape"]
        assert "name" in opt_schema["required"]
        # label has a default, so it should not be required.
        assert "label" not in opt_schema.get("required", [])
