# -*- coding: utf-8 -*-
import copy

from django import forms
from django_filters import Filter, FilterSet
from django_filters.fields import Lookup
from django_filters.filters import EMPTY_VALUES


class ListOrCommaSeparatedStringMixin:
    def filter(self, qs, value):
        # todo: test me
        if value:
            self.lookup_expr = 'in'
            if isinstance(value, str):
                value = value.split(',')
        else:
            value = None
        return super().filter(qs, value)


class ListOrCommaSeparatedStringFilter(ListOrCommaSeparatedStringMixin, Filter):
    pass


class ListFilter(Filter):
    def filter(self, qs, value):
        if isinstance(value, Lookup):
            lookup = value.lookup_expr
            value = value.value
        else:
            lookup = self.lookup_expr

        if value in EMPTY_VALUES:
            return qs

        new_qs = []
        for it in qs:
            if lookup == 'exact':
                if it.get(self.field_name) == value:
                    new_qs.append(it)
            elif lookup == 'startswith':
                if it.get(self.field_name).startswith(value):
                    new_qs.append(it)
            elif lookup == 'in':
                if it.get(self.field_name) in set(value):
                    new_qs.append(it)
        return new_qs


class ListOrCommaSeparatedStringListFilter(ListOrCommaSeparatedStringMixin, ListFilter):
    pass


class CharListFilter(ListFilter):
    field_class = forms.CharField


class ListFilterSet(FilterSet):
    def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
        self.is_bound = data is not None
        self.data = data or {}
        self.queryset = queryset
        self.request = request
        self.form_prefix = prefix
        self.filters = copy.deepcopy(self.base_filters)

    @property
    def qs(self):
        if not hasattr(self, '_qs'):
            self._qs = self.filter_queryset(self.queryset)
        return self._qs

    def filter_queryset(self, queryset):
        valid = self.is_bound and self.form.is_valid()
        for name, filter_ in self.filters.items():
            value = None
            if valid:
                value = self.form.cleaned_data[name]
            else:
                raw_value = self.form[name].value()
                try:
                    value = self.form.fields[name].clean(raw_value)
                except forms.ValidationError:
                    return []
            if value is not None:  # valid & clean data
                queryset = filter_.filter(queryset, value)
        return queryset
