
from __future__ import absolute_import
import warnings

from django.template import loader
from django.utils import six

from .. import compat
from . import filterset, filters


class DjangoFilterBackend(object):
    default_filter_set = filterset.FilterSet

    @property
    def template(self):
        if compat.is_crispy():
            return 'jet_django.deps.django_filters/rest_framework/crispy_form.html'
        return 'jet_django.deps.django_filters/rest_framework/form.html'

    def get_filter_class(self, view, queryset=None):
        """
        Return the django-filters `FilterSet` used to filter the queryset.
        """
        filter_class = getattr(view, 'filter_class', None)
        filter_fields = getattr(view, 'filter_fields', None)

        if filter_class:
            filter_model = filter_class.Meta.model

            assert issubclass(queryset.model, filter_model), \
                'FilterSet model %s does not match queryset model %s' % \
                (filter_model, queryset.model)

            return filter_class

        if filter_fields:
            MetaBase = getattr(self.default_filter_set, 'Meta', object)

            class AutoFilterSet(self.default_filter_set):
                class Meta(MetaBase):
                    model = queryset.model
                    fields = filter_fields

            return AutoFilterSet

        return None

    def filter_queryset(self, request, queryset, view):
        filter_class = self.get_filter_class(view, queryset)

        if filter_class:
            return filter_class(request.query_params, queryset=queryset, request=request).qs

        return queryset

    def to_html(self, request, queryset, view):
        filter_class = self.get_filter_class(view, queryset)
        if not filter_class:
            return None
        filter_instance = filter_class(request.query_params, queryset=queryset, request=request)

        template = loader.get_template(self.template)
        context = {
            'filter': filter_instance
        }

        return template.render(context, request)

    def get_coreschema_field(self, field):
        if isinstance(field, filters.NumberFilter):
            field_cls = compat.coreschema.Number
        else:
            field_cls = compat.coreschema.String
        return field_cls(
            description=six.text_type(field.extra.get('help_text', ''))
        )

    def get_schema_fields(self, view):
        # This is not compatible with widgets where the query param differs from the
        # filter's attribute name. Notably, this includes `MultiWidget`, where query
        # params will be of the format `<name>_0`, `<name>_1`, etc...
        assert compat.coreapi is not None, 'coreapi must be installed to use `get_schema_fields()`'
        assert compat.coreschema is not None, 'coreschema must be installed to use `get_schema_fields()`'

        filter_class = getattr(view, 'filter_class', None)
        if filter_class is None:
            try:
                filter_class = self.get_filter_class(view, view.get_queryset())
            except Exception:
                warnings.warn(
                    "{} is not compatible with schema generation".format(view.__class__)
                )
                filter_class = None

        return [] if not filter_class else [
            compat.coreapi.Field(
                name=field_name,
                required=False,
                location='query',
                schema=self.get_coreschema_field(field)
                )
            for field_name, field in filter_class.base_filters.items()
        ]
