import django_filters
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.utils.translation import gettext as _

from core.models import DataSource, ObjectType
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet
from tenancy.models import Tenant, TenantGroup
from users.filterset_mixins import OwnerFilterMixin
from users.models import Group, User
from utilities.filters import MultiValueCharFilter, MultiValueContentTypeFilter, MultiValueNumberFilter
from utilities.filtersets import register_filterset
from virtualization.models import Cluster, ClusterGroup, ClusterType

from .choices import *
from .filters import TagFilter, TagIDFilter
from .models import *

__all__ = (
    'BookmarkFilterSet',
    'ConfigContextFilterSet',
    'ConfigContextProfileFilterSet',
    'ConfigTemplateFilterSet',
    'CustomFieldChoiceSetFilterSet',
    'CustomFieldFilterSet',
    'CustomLinkFilterSet',
    'EventRuleFilterSet',
    'ExportTemplateFilterSet',
    'ImageAttachmentFilterSet',
    'JournalEntryFilterSet',
    'LocalConfigContextFilterSet',
    'NotificationGroupFilterSet',
    'SavedFilterFilterSet',
    'ScriptFilterSet',
    'TableConfigFilterSet',
    'TagFilterSet',
    'TaggedItemFilterSet',
    'WebhookFilterSet',
)


@register_filterset
class ScriptFilterSet(BaseFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    module_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ScriptModule.objects.all(),
        distinct=False,
        label=_('Script module (ID)'),
    )

    class Meta:
        model = Script
        fields = ('id', 'name', 'is_executable')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value)
        )


@register_filterset
class WebhookFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    http_method = django_filters.MultipleChoiceFilter(
        choices=WebhookHttpMethodChoices,
        distinct=False,
    )
    payload_url = MultiValueCharFilter(
        lookup_expr='icontains'
    )

    class Meta:
        model = Webhook
        fields = (
            'id', 'name', 'payload_url', 'http_method', 'http_content_type', 'secret', 'ssl_verification',
            'ca_file_path', 'description',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value) |
            Q(payload_url__icontains=value)
        )


@register_filterset
class EventRuleFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        field_name='object_types'
    )
    object_type = MultiValueContentTypeFilter(
        field_name='object_types'
    )
    event_type = MultiValueCharFilter(
        method='filter_event_type'
    )
    action_type = django_filters.MultipleChoiceFilter(
        choices=EventRuleActionChoices,
        distinct=False,
    )
    action_object_type = MultiValueContentTypeFilter()
    action_object_id = MultiValueNumberFilter()

    class Meta:
        model = EventRule
        fields = (
            'id', 'name', 'enabled', 'action_type', 'description',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value) |
            Q(comments__icontains=value)
        )

    def filter_event_type(self, queryset, name, value):
        return queryset.filter(event_types__overlap=value)


@register_filterset
class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    type = django_filters.MultipleChoiceFilter(
        choices=CustomFieldTypeChoices,
        distinct=False,
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        field_name='object_types'
    )
    object_type = MultiValueContentTypeFilter(
        field_name='object_types'
    )
    related_object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        distinct=False,
        field_name='related_object_type'
    )
    related_object_type = MultiValueContentTypeFilter()
    choice_set_id = django_filters.ModelMultipleChoiceFilter(
        queryset=CustomFieldChoiceSet.objects.all(),
        distinct=False,
    )
    choice_set = django_filters.ModelMultipleChoiceFilter(
        field_name='choice_set__name',
        queryset=CustomFieldChoiceSet.objects.all(),
        distinct=False,
        to_field_name='name'
    )

    class Meta:
        model = CustomField
        fields = (
            'id', 'name', 'label', 'group_name', 'required', 'unique', 'search_weight', 'filter_logic', 'ui_visible',
            'ui_editable', 'weight', 'is_cloneable', 'nulls_first', 'description', 'validation_minimum',
            'validation_maximum', 'validation_regex',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(label__icontains=value) |
            Q(group_name__icontains=value) |
            Q(description__icontains=value) |
            Q(comments__icontains=value)
        )


@register_filterset
class CustomFieldChoiceSetFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    choice = MultiValueCharFilter(
        method='filter_by_choice'
    )
    choice_colors = django_filters.MultipleChoiceFilter(
        choices=CustomFieldChoiceColorChoices,
        method='filter_by_choice_colors',
        label=_('Choice colors'),
        distinct=False,
    )

    class Meta:
        model = CustomFieldChoiceSet
        fields = (
            'id', 'name', 'description', 'base_choices', 'order_alphabetically',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value)
        )

    def filter_by_choice(self, queryset, name, value):
        # TODO: Support case-insensitive matching
        return queryset.filter(extra_choices__overlap=value)

    def filter_by_choice_colors(self, queryset, name, value):
        if not value:
            return queryset

        choice_color_keys = set()
        for choice_colors in queryset.values_list('choice_colors', flat=True):
            if isinstance(choice_colors, dict):
                choice_color_keys.update(choice_colors.keys())

        if not choice_color_keys:
            return queryset.none()

        params = Q()
        for key in choice_color_keys:
            for color in value:
                params |= Q(choice_colors__contains={key: color})

        return queryset.filter(params)


@register_filterset
class CustomLinkFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        field_name='object_types'
    )
    object_type = MultiValueContentTypeFilter(
        field_name='object_types'
    )

    class Meta:
        model = CustomLink
        fields = (
            'id', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name', 'new_window', 'button_class',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(link_text__icontains=value) |
            Q(link_url__icontains=value) |
            Q(group_name__icontains=value)
        )


@register_filterset
class ExportTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        field_name='object_types'
    )
    object_type = MultiValueContentTypeFilter(
        field_name='object_types'
    )
    data_source_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data source (ID)'),
    )
    data_file_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data file (ID)'),
    )

    class Meta:
        model = ExportTemplate
        fields = (
            'id', 'name', 'description', 'mime_type', 'file_name', 'file_extension', 'as_attachment',
            'auto_sync_enabled', 'data_synced',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value) |
            Q(file_name__icontains=value)
        )


@register_filterset
class SavedFilterFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        field_name='object_types'
    )
    object_type = MultiValueContentTypeFilter(
        field_name='object_types'
    )
    user_id = django_filters.ModelMultipleChoiceFilter(
        queryset=User.objects.all(),
        distinct=False,
        label=_('User (ID)'),
    )
    user = django_filters.ModelMultipleChoiceFilter(
        field_name='user__username',
        queryset=User.objects.all(),
        distinct=False,
        to_field_name='username',
        label=_('User (name)'),
    )
    usable = django_filters.BooleanFilter(
        method='_usable'
    )

    class Meta:
        model = SavedFilter
        fields = ('id', 'name', 'slug', 'description', 'enabled', 'shared', 'weight')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value)
        )

    def _usable(self, queryset, name, value):
        """
        Return only SavedFilters that are both enabled and are shared (or belong to the current user).
        """
        user = self.request.user if self.request else None
        if not user or user.is_anonymous:
            if value:
                return queryset.filter(enabled=True, shared=True)
            return queryset.filter(Q(enabled=False) | Q(shared=False))
        if value:
            return queryset.filter(enabled=True).filter(Q(shared=True) | Q(user=user))
        return queryset.filter(Q(enabled=False) | Q(Q(shared=False) & ~Q(user=user)))


@register_filterset
class TableConfigFilterSet(ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.all(),
        distinct=False,
        field_name='object_type'
    )
    object_type = MultiValueContentTypeFilter(
        field_name='object_type'
    )
    user_id = django_filters.ModelMultipleChoiceFilter(
        queryset=User.objects.all(),
        distinct=False,
        label=_('User (ID)'),
    )
    user = django_filters.ModelMultipleChoiceFilter(
        field_name='user__username',
        queryset=User.objects.all(),
        distinct=False,
        to_field_name='username',
        label=_('User (name)'),
    )
    usable = django_filters.BooleanFilter(
        method='_usable'
    )

    class Meta:
        model = TableConfig
        fields = ('id', 'name', 'description', 'table', 'enabled', 'shared', 'weight')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value) |
            Q(table__icontains=value)
        )

    def _usable(self, queryset, name, value):
        """
        Return only TableConfigs that are both enabled and are shared (or belong to the current user).
        """
        user = self.request.user if self.request else None
        if not user or user.is_anonymous:
            if value:
                return queryset.filter(enabled=True, shared=True)
            return queryset.filter(Q(enabled=False) | Q(shared=False))
        if value:
            return queryset.filter(enabled=True).filter(Q(shared=True) | Q(user=user))
        return queryset.filter(Q(enabled=False) | Q(Q(shared=False) & ~Q(user=user)))


@register_filterset
class BookmarkFilterSet(BaseFilterSet):
    created = django_filters.DateTimeFilter()
    object_type_id = MultiValueNumberFilter()
    object_type = MultiValueContentTypeFilter()
    user_id = django_filters.ModelMultipleChoiceFilter(
        queryset=User.objects.all(),
        distinct=False,
        label=_('User (ID)'),
    )
    user = django_filters.ModelMultipleChoiceFilter(
        field_name='user__username',
        queryset=User.objects.all(),
        distinct=False,
        to_field_name='username',
        label=_('User (name)'),
    )

    class Meta:
        model = Bookmark
        fields = ('id', 'object_id')


@register_filterset
class NotificationGroupFilterSet(ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    user_id = django_filters.ModelMultipleChoiceFilter(
        field_name='users',
        queryset=User.objects.all(),
        label=_('User (ID)'),
    )
    user = django_filters.ModelMultipleChoiceFilter(
        field_name='users__username',
        queryset=User.objects.all(),
        to_field_name='username',
        label=_('User (name)'),
    )
    group_id = django_filters.ModelMultipleChoiceFilter(
        field_name='groups',
        queryset=Group.objects.all(),
        label=_('Group (ID)'),
    )
    group = django_filters.ModelMultipleChoiceFilter(
        field_name='groups__name',
        queryset=Group.objects.all(),
        to_field_name='name',
        label=_('Group (name)'),
    )

    class Meta:
        model = NotificationGroup
        fields = (
            'id', 'name', 'description',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value)
        )


@register_filterset
class ImageAttachmentFilterSet(ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type = MultiValueContentTypeFilter()

    class Meta:
        model = ImageAttachment
        fields = (
            'id', 'object_type_id', 'object_id', 'name', 'description', 'image_width', 'image_height', 'image_size',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(image__icontains=value) |
            Q(description__icontains=value)
        )


@register_filterset
class JournalEntryFilterSet(NetBoxModelFilterSet):
    created = django_filters.DateTimeFromToRangeFilter()
    assigned_object_type = MultiValueContentTypeFilter()
    assigned_object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ContentType.objects.all(),
        distinct=False,
    )
    created_by_id = django_filters.ModelMultipleChoiceFilter(
        queryset=User.objects.all(),
        distinct=False,
        label=_('User (ID)'),
    )
    created_by = django_filters.ModelMultipleChoiceFilter(
        field_name='created_by__username',
        queryset=User.objects.all(),
        distinct=False,
        to_field_name='username',
        label=_('User (name)'),
    )
    kind = django_filters.MultipleChoiceFilter(
        choices=JournalEntryKindChoices,
        distinct=False,
    )

    class Meta:
        model = JournalEntry
        fields = ('id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(comments__icontains=value)


@register_filterset
class TagFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    content_type = MultiValueCharFilter(
        method='_content_type'
    )
    content_type_id = MultiValueNumberFilter(
        method='_content_type_id'
    )
    for_object_type_id = MultiValueNumberFilter(
        method='_for_object_type'
    )

    class Meta:
        model = Tag
        fields = ('id', 'name', 'slug', 'color', 'weight', 'description', 'object_types')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(slug__icontains=value) |
            Q(description__icontains=value)
        )

    def _content_type(self, queryset, name, values):
        ct_filter = Q()

        # Compile list of app_label & model pairings
        for value in values:
            try:
                app_label, model = value.lower().split('.')
                ct_filter |= Q(
                    app_label=app_label,
                    model=model
                )
            except ValueError:
                pass

        # Get ContentType instances
        content_types = ContentType.objects.filter(ct_filter)

        return queryset.filter(extras_taggeditem_items__content_type__in=content_types).distinct()

    def _content_type_id(self, queryset, name, values):

        # Get ContentType instances
        content_types = ContentType.objects.filter(pk__in=values)

        return queryset.filter(extras_taggeditem_items__content_type__in=content_types).distinct()

    def _for_object_type(self, queryset, name, values):
        return queryset.filter(
            Q(object_types__id__in=values) | Q(object_types__isnull=True)
        )


@register_filterset
class TaggedItemFilterSet(BaseFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type = MultiValueContentTypeFilter(
        field_name='content_type'
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ContentType.objects.all(),
        distinct=False,
        field_name='content_type_id'
    )
    tag_id = django_filters.ModelMultipleChoiceFilter(
        queryset=Tag.objects.all(),
        distinct=False,
    )
    tag = django_filters.ModelMultipleChoiceFilter(
        field_name='tag__slug',
        queryset=Tag.objects.all(),
        distinct=False,
        to_field_name='slug',
    )

    class Meta:
        model = TaggedItem
        fields = ('id', 'object_id')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(tag__name__icontains=value) |
            Q(tag__slug__icontains=value) |
            Q(tag__description__icontains=value)
        )


@register_filterset
class ConfigContextProfileFilterSet(PrimaryModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    data_source_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data source (ID)'),
    )
    data_file_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data file (ID)'),
    )

    class Meta:
        model = ConfigContextProfile
        fields = (
            'id', 'name', 'description', 'auto_sync_enabled', 'data_synced',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value) |
            Q(comments__icontains=value)
        )


@register_filterset
class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    profile_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ConfigContextProfile.objects.all(),
        distinct=False,
        label=_('Profile (ID)'),
    )
    profile = django_filters.ModelMultipleChoiceFilter(
        field_name='profile__name',
        queryset=ConfigContextProfile.objects.all(),
        distinct=False,
        to_field_name='name',
        label=_('Profile (name)'),
    )
    region_id = django_filters.ModelMultipleChoiceFilter(
        field_name='regions',
        queryset=Region.objects.all(),
        label=_('Region'),
    )
    region = django_filters.ModelMultipleChoiceFilter(
        field_name='regions__slug',
        queryset=Region.objects.all(),
        to_field_name='slug',
        label=_('Region (slug)'),
    )
    site_group = django_filters.ModelMultipleChoiceFilter(
        field_name='site_groups__slug',
        queryset=SiteGroup.objects.all(),
        to_field_name='slug',
        label=_('Site group (slug)'),
    )
    site_group_id = django_filters.ModelMultipleChoiceFilter(
        field_name='site_groups',
        queryset=SiteGroup.objects.all(),
        label=_('Site group'),
    )
    site_id = django_filters.ModelMultipleChoiceFilter(
        field_name='sites',
        queryset=Site.objects.all(),
        label=_('Site'),
    )
    site = django_filters.ModelMultipleChoiceFilter(
        field_name='sites__slug',
        queryset=Site.objects.all(),
        to_field_name='slug',
        label=_('Site (slug)'),
    )
    location_id = django_filters.ModelMultipleChoiceFilter(
        field_name='locations',
        queryset=Location.objects.all(),
        label=_('Location'),
    )
    location = django_filters.ModelMultipleChoiceFilter(
        field_name='locations__slug',
        queryset=Location.objects.all(),
        to_field_name='slug',
        label=_('Location (slug)'),
    )
    device_type_id = django_filters.ModelMultipleChoiceFilter(
        field_name='device_types',
        queryset=DeviceType.objects.all(),
        label=_('Device type'),
    )
    device_role_id = django_filters.ModelMultipleChoiceFilter(
        field_name='roles',
        queryset=DeviceRole.objects.all(),
        label=_('Role'),
    )
    device_role = django_filters.ModelMultipleChoiceFilter(
        field_name='roles__slug',
        queryset=DeviceRole.objects.all(),
        to_field_name='slug',
        label=_('Role (slug)'),
    )
    platform_id = django_filters.ModelMultipleChoiceFilter(
        field_name='platforms',
        queryset=Platform.objects.all(),
        label=_('Platform'),
    )
    platform = django_filters.ModelMultipleChoiceFilter(
        field_name='platforms__slug',
        queryset=Platform.objects.all(),
        to_field_name='slug',
        label=_('Platform (slug)'),
    )
    cluster_type_id = django_filters.ModelMultipleChoiceFilter(
        field_name='cluster_types',
        queryset=ClusterType.objects.all(),
        label=_('Cluster type'),
    )
    cluster_type = django_filters.ModelMultipleChoiceFilter(
        field_name='cluster_types__slug',
        queryset=ClusterType.objects.all(),
        to_field_name='slug',
        label=_('Cluster type (slug)'),
    )
    cluster_group_id = django_filters.ModelMultipleChoiceFilter(
        field_name='cluster_groups',
        queryset=ClusterGroup.objects.all(),
        label=_('Cluster group'),
    )
    cluster_group = django_filters.ModelMultipleChoiceFilter(
        field_name='cluster_groups__slug',
        queryset=ClusterGroup.objects.all(),
        to_field_name='slug',
        label=_('Cluster group (slug)'),
    )
    cluster_id = django_filters.ModelMultipleChoiceFilter(
        field_name='clusters',
        queryset=Cluster.objects.all(),
        label=_('Cluster'),
    )
    tenant_group_id = django_filters.ModelMultipleChoiceFilter(
        field_name='tenant_groups',
        queryset=TenantGroup.objects.all(),
        label=_('Tenant group'),
    )
    tenant_group = django_filters.ModelMultipleChoiceFilter(
        field_name='tenant_groups__slug',
        queryset=TenantGroup.objects.all(),
        to_field_name='slug',
        label=_('Tenant group (slug)'),
    )
    tenant_id = django_filters.ModelMultipleChoiceFilter(
        field_name='tenants',
        queryset=Tenant.objects.all(),
        label=_('Tenant'),
    )
    tenant = django_filters.ModelMultipleChoiceFilter(
        field_name='tenants__slug',
        queryset=Tenant.objects.all(),
        to_field_name='slug',
        label=_('Tenant (slug)'),
    )
    tag_id = django_filters.ModelMultipleChoiceFilter(
        field_name='tags',
        queryset=Tag.objects.all(),
        label=_('Tag'),
    )
    tag = django_filters.ModelMultipleChoiceFilter(
        field_name='tags__slug',
        queryset=Tag.objects.all(),
        to_field_name='slug',
        label=_('Tag (slug)'),
    )
    data_source_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data source (ID)'),
    )
    data_file_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data file (ID)'),
    )

    class Meta:
        model = ConfigContext
        fields = ('id', 'name', 'is_active', 'description', 'weight', 'auto_sync_enabled', 'data_synced')

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value) |
            Q(data__icontains=value)
        )


@register_filterset
class ConfigTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    data_source_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data source (ID)'),
    )
    data_file_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data file (ID)'),
    )
    tag = TagFilter()
    tag_id = TagIDFilter()

    class Meta:
        model = ConfigTemplate
        fields = (
            'id', 'name', 'description', 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'debug',
            'auto_sync_enabled', 'data_synced'
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(name__icontains=value) |
            Q(description__icontains=value)
        )


#
# Filter for Local Config Context Data
#

class LocalConfigContextFilterSet(django_filters.FilterSet):
    local_context_data = django_filters.BooleanFilter(
        method='_local_context_data',
        label=_('Has local config context data'),
    )

    def _local_context_data(self, queryset, name, value):
        return queryset.exclude(local_context_data__isnull=value)
