from typing import Any, Dict, List, Optional, Sequence, Type, TypeVar, Union, overload

from django.db.models import Manager, Model
from django.db.models.query import QuerySet
from django.http.response import HttpResponse

from mongoengine import QuerySet as MongoQuerySet
from rest_framework import mixins, views
from rest_framework.filters import BaseFilterBackend
from rest_framework.pagination import BasePagination
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer

_MT_co = TypeVar("_MT_co", bound=Model, covariant=True)

def get_object_or_404(
    queryset: Union[Type[_MT_co], Manager[_MT_co], QuerySet[_MT_co]], *filter_args: Any, **filter_kwargs: Any
) -> _MT_co: ...

_T = TypeVar("_T")
_D = TypeVar("_D", bound=Model)

_Q = TypeVar("_Q", bound=Union[QuerySet[Any], MongoQuerySet[Any]])

class GenericAPIView(views.APIView):
    serializer_class: Optional[Type[BaseSerializer]] = ...
    lookup_field: str = ...
    lookup_url_kwarg: Optional[str] = ...
    filter_backends: Sequence[Type[BaseFilterBackend]] = ...
    pagination_class: Optional[Type[BasePagination]] = ...
    def get_object(self) -> Any: ...
    def get_serializer(self, *args: Any, **kwargs: Any) -> BaseSerializer: ...
    def get_serializer_class(self) -> Type[BaseSerializer]: ...
    def get_serializer_context(self) -> Dict[str, Any]: ...
    def filter_queryset(self, queryset: _Q) -> _Q: ...
    @property
    def paginator(self) -> Optional[BasePagination]: ...
    @overload
    def paginate_queryset(self, queryset: QuerySet[_D]) -> Optional[List[_D]]: ...
    @overload
    def paginate_queryset(self, queryset: MongoQuerySet[_T]) -> Optional[List[_T]]: ...
    def get_paginated_response(self, data: Any) -> Response: ...

class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):
    def post(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class ListAPIView(mixins.ListModelMixin, GenericAPIView):
    def get(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView):
    def get(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView):
    def delete(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView):
    def put(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def patch(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class ListCreateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, GenericAPIView):
    def get(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def post(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class RetrieveUpdateAPIView(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, GenericAPIView):
    def get(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def put(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def patch(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class RetrieveDestroyAPIView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, GenericAPIView):
    def get(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def delete(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...

class RetrieveUpdateDestroyAPIView(
    mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, GenericAPIView
):
    def get(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def put(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def patch(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
    def delete(self, request: Request, *args: Any, **kwargs: Any) -> HttpResponse: ...
