# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals

import coreapi
import coreschema
from django import forms
from django.db.models.constants import LOOKUP_SEP

from ..fields import MultipleValuesField
from ..filtersets import FilterSet
from .drf import URLFilterBackend


DESCRIPTION = {
    'contains': 'Match when string contains given substring',
    'day': 'Match by day of the month',
    'endswith': 'Match when string ends with given substring',
    'exact': 'Match exactly the value as is',
    'gt': 'Match when value is greater then given value',
    'gte': 'Match when value is greater or equal then given value',
    'hour': 'Match by the hour (24 hour) value of the timestamp',
    'icontains': 'Case insensitive match when string contains given substring',
    'iendswith': 'Case insensitive match when string ends with given substring',
    'iexact': 'Case insensitive match exactly the value as is',
    'iin': 'Case insensitive match when value is any of given comma separated values',
    'in': 'Match when value is any of given comma separated values',
    'iregex': 'Case insensitive match when value is within comma separated range',
    'isnull': 'Match when value is NULL',
    'istartswith': 'Case insensitive match when string starts with given substring',
    'lt': 'Match when value is less then given value',
    'lte': 'Match when value is less or equal then given value',
    'minute': 'Match by the minute value of the timestamp',
    'month': 'Match by the month value of the timestamp',
    'range': 'Match when value is within comma separated range',
    'regex': 'Match string by regex pattern',
    'second': 'Match by the second value of the timestamp',
    'startswith': 'Match when string starts with given substring',
    'week_day': 'Match by week day (1-Sunday to 7-Saturday) of the timestamp',
    'year': 'Match by the year value of the timestamp',
}

FORM_FIELD_TO_SCHEMA = {
    MultipleValuesField: coreschema.Array,
    forms.BooleanField: coreschema.Boolean,
    forms.IntegerField: coreschema.Integer,
    forms.FloatField: coreschema.Number,
}


def _field_to_schema(field, lookup):
    form_field = field.get_form_field(lookup)
    return FORM_FIELD_TO_SCHEMA.get(type(form_field), coreschema.String)(description=DESCRIPTION.get(lookup))


def _all_filters(filterset, prefix=()):
    for name, field in filterset.filters.items():
        if isinstance(field, FilterSet):
            for i in _all_filters(field, prefix=prefix + (name,)):
                yield i

        else:
            yield coreapi.Field(
                name=LOOKUP_SEP.join(prefix + (name,)),
                required=False,
                location="query",
                schema=_field_to_schema(field, field.default_lookup),
            )
            if field.no_lookup:
                continue
            for lookup in field.lookups:
                yield coreapi.Field(
                    name=LOOKUP_SEP.join(prefix + (name, lookup)),
                    required=False,
                    location="query",
                    schema=_field_to_schema(field, lookup),
                )


class CoreAPIURLFilterBackend(URLFilterBackend):
    """
    Same as :py:class:`url_filter.integrations.drf.DjangoFilterBackend` except
    this backend also implements coreapi interface for autogenerated API docs.
    """

    def get_schema_fields(self, view):
        """
        Get coreapi filter definitions

        Returns all filters including their supported lookups.
        """
        queryset = view.get_queryset()
        filter_class = self.get_filter_class(view, queryset)

        return (
            []
            if not filter_class
            else list(_all_filters(filter_class(data={}, queryset=queryset)))
        )
