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

from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, PrimaryModelFilterSet
from netbox.utils import get_data_backend_choices
from users.models import User
from utilities.filters import MultiValueContentTypeFilter
from utilities.filtersets import register_filterset

from .choices import *
from .models import *

__all__ = (
    'ConfigRevisionFilterSet',
    'DataFileFilterSet',
    'DataSourceFilterSet',
    'JobFilterSet',
    'ObjectChangeFilterSet',
    'ObjectTypeFilterSet',
)


@register_filterset
class DataSourceFilterSet(PrimaryModelFilterSet):
    type = django_filters.MultipleChoiceFilter(
        choices=get_data_backend_choices,
        distinct=False,
        null_value=None
    )
    status = django_filters.MultipleChoiceFilter(
        choices=DataSourceStatusChoices,
        distinct=False,
        null_value=None
    )
    sync_interval = django_filters.MultipleChoiceFilter(
        choices=JobIntervalChoices,
        distinct=False,
        null_value=None
    )

    class Meta:
        model = DataSource
        fields = ('id', 'name', 'enabled', 'description', 'source_url', 'last_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 DataFileFilterSet(ChangeLoggedModelFilterSet):
    q = django_filters.CharFilter(
        method='search'
    )
    source_id = django_filters.ModelMultipleChoiceFilter(
        queryset=DataSource.objects.all(),
        distinct=False,
        label=_('Data source (ID)'),
    )
    source = django_filters.ModelMultipleChoiceFilter(
        field_name='source__name',
        queryset=DataSource.objects.all(),
        distinct=False,
        to_field_name='name',
        label=_('Data source (name)'),
    )

    class Meta:
        model = DataFile
        fields = ('id', 'path', 'last_updated', 'size', 'hash')

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


@register_filterset
class JobFilterSet(BaseFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ObjectType.objects.with_feature('jobs'),
        distinct=False,
        field_name='object_type_id',
    )
    object_type = MultiValueContentTypeFilter()
    created = django_filters.DateTimeFilter()
    created__before = django_filters.DateTimeFilter(
        field_name='created',
        lookup_expr='lte'
    )
    created__after = django_filters.DateTimeFilter(
        field_name='created',
        lookup_expr='gte'
    )
    scheduled = django_filters.DateTimeFilter()
    scheduled__before = django_filters.DateTimeFilter(
        field_name='scheduled',
        lookup_expr='lte'
    )
    scheduled__after = django_filters.DateTimeFilter(
        field_name='scheduled',
        lookup_expr='gte'
    )
    started = django_filters.DateTimeFilter()
    started__before = django_filters.DateTimeFilter(
        field_name='started',
        lookup_expr='lte'
    )
    started__after = django_filters.DateTimeFilter(
        field_name='started',
        lookup_expr='gte'
    )
    completed = django_filters.DateTimeFilter()
    completed__before = django_filters.DateTimeFilter(
        field_name='completed',
        lookup_expr='lte'
    )
    completed__after = django_filters.DateTimeFilter(
        field_name='completed',
        lookup_expr='gte'
    )
    status = django_filters.MultipleChoiceFilter(
        choices=JobStatusChoices,
        distinct=False,
        null_value=None
    )
    notifications = django_filters.MultipleChoiceFilter(
        choices=JobNotificationChoices,
        distinct=False,
        null_value=None
    )
    queue_name = django_filters.CharFilter()
    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 = Job
        fields = (
            'id', 'object_type', 'object_type_id', 'object_id', 'name', 'interval', 'status', 'user', 'job_id',
            'queue_name',
        )

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


@register_filterset
class ObjectTypeFilterSet(BaseFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    features = django_filters.CharFilter(
        method='filter_features'
    )

    class Meta:
        model = ObjectType
        fields = ('id', 'app_label', 'model', 'public')

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

    def filter_features(self, queryset, name, value):
        return queryset.filter(features__icontains=value)


@register_filterset
class ObjectChangeFilterSet(BaseFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )
    time = django_filters.DateTimeFromToRangeFilter()
    changed_object_type = MultiValueContentTypeFilter()
    changed_object_type_id = django_filters.ModelMultipleChoiceFilter(
        queryset=ContentType.objects.all(),
        distinct=False,
    )
    related_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 = ObjectChange
        fields = (
            'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id',
            'related_object_type', 'related_object_id', 'object_repr',
        )

    def search(self, queryset, name, value):
        if not value.strip():
            return queryset
        return queryset.filter(
            Q(user_name__icontains=value) |
            Q(object_repr__icontains=value) |
            Q(message__icontains=value)
        )


@register_filterset
class ConfigRevisionFilterSet(BaseFilterSet):
    q = django_filters.CharFilter(
        method='search',
        label=_('Search'),
    )

    class Meta:
        model = ConfigRevision
        fields = ('id', 'created', 'comment')

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