"""_____________________________________________________________________

:PROJECT: LARAsuite

*lara_django_data filter app *

:details: lara_django_data filter app.
         -
:authors: mark doerr <mark.doerr@uni-greifswald.de>

.. note:: -
.. todo:: -
________________________________________________________________________
"""

import django_filters
from django.db.models import Q
from django_filters.rest_framework import FilterSet

from .models import (
    Address,
    City,
    Country,
    CountrySubdivision,
    Currency,
    DataType,
    ExternalResource,
    ExtraData,
    GeoLocation,
    ItemStatus,
    LARASyncServer,
    Location,
    MediaType,
    Namespace,
    PhysicalStateMatter,
    PhysicalUnit,
    Room,
    RoomCategory,
    ScientificConstant,
    SubdivisionType,
    Tag,
)


class MediaTypeFilterSet(FilterSet):
    class Meta:
        model = MediaType
        fields = {
            "name": ["exact", "contains"],
            "media_type": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class DataTypeFilterSet(FilterSet):
    class Meta:
        model = DataType
        fields = {
            "name": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class NamespaceFilterSet(FilterSet):
    # uri =CharFilter(field_name="uri", lookup_expr="contains")
    class Meta:
        model = Namespace
        fields = {
            "uri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class TagFilterSet(FilterSet):
    class Meta:
        model = Tag
        fields = {
            "tag": ["exact", "contains"],
            "iri": ["exact", "contains"],
        }


class ItemStatusFilterSet(FilterSet):
    class Meta:
        model = ItemStatus
        fields = {
            "status": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class ExtraDataFilterSet(FilterSet):
    class Meta:
        model = ExtraData
        fields = {
            "namespace__uri": ["exact", "contains"],
            "name_display": ["exact", "contains"],
            "name": ["exact", "contains"],
            "name_full": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "url": ["exact", "contains"],
            "datetime_created": ["lt", "gt", "exact", "range"],
            "datetime_last_modified": ["lt", "gt", "exact", "range"],
            "description": ["exact", "contains"],
        }


class ExternalResourceFilterSet(FilterSet):
    """This filter is used to filter ExternalResource objects by name, description and URL."""

    class Meta:
        model = ExternalResource
        fields = {
            "name": ["exact", "contains"],
            "name_display": ["exact", "contains"],
            "url": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
            "datetime_last_modified": ["lt", "gt", "exact", "range"],
        }


class PhysicalUnitFilterSet(FilterSet):
    class Meta:
        model = PhysicalUnit
        fields = {
            "name": ["exact", "contains"],
            "symbol": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class PhysicalStateMatterFilterSet(FilterSet):
    class Meta:
        model = PhysicalStateMatter
        fields = {
            "name": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class ScientificConstantFilterSet(FilterSet):
    class Meta:
        model = ScientificConstant
        fields = {
            "name": ["exact", "contains"],
            "symbol": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "url_source": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class CurrencyFilterSet(FilterSet):
    class Meta:
        model = Currency
        fields = {
            "name": ["exact", "contains"],
            "symbol": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "datetime_last_modified": ["lt", "gt", "exact", "range"],
        }


class GeoLocationFilterSet(FilterSet):
    class Meta:
        model = GeoLocation
        fields = {
            "name": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "datetime_last_modified": ["lt", "gt", "exact", "range"],
        }


class CountryFilterSet(FilterSet):
    class Meta:
        model = Country
        fields = {
            "name": ["exact", "contains"],
            "name_local": ["exact", "contains"],
            "alpha2code": ["exact", "contains"],
            "alpha3code": ["exact", "contains"],
            "numeric_code": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class SubdivisionTypeFilterSet(FilterSet):
    class Meta:
        model = SubdivisionType
        fields = {
            "name": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class CountrySubdivisionFilterSet(FilterSet):
    class Meta:
        model = CountrySubdivision
        fields = {
            "name": ["exact", "contains"],
            "name_local": ["exact", "contains"],
            "code": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class CityFilterSet(FilterSet):
    class Meta:
        model = City
        fields = {
            "name": ["exact", "contains"],
            "name_local": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class AddressFilterSet(FilterSet):
    name = django_filters.CharFilter(method="filter_name")

    class Meta:
        model = Address
        fields = {
            "namespace__uri": ["exact", "contains"],
            "building": ["exact", "contains"],
            "street": ["exact", "contains"],
            "house_number": ["exact"],
            "postal_code": ["exact"],
            "city__name": ["exact", "contains"],
            "city__name_local": ["exact", "contains"],
            "country__name": ["exact", "contains"],
            "country__name_local": ["exact", "contains"],
            "country__alpha2code": ["exact"],
            "supplement": ["exact", "contains"],
            "description": ["exact", "contains"],
        }
    
    def filter_name(self, queryset, name, value):
        # Simulate searching by the "name" property using the real fields

        tokens = value.strip().split()
        if not tokens:
            return queryset.filter(
                Q(street__icontains=value)
                | Q(building__icontains=value)
                | Q(house_number__icontains=value)
                | Q(postal_code__icontains=value)
                | Q(city__name__icontains=value)
                | Q(country__name__icontains=value)
            )
        for token in tokens:
            queryset = queryset.filter(
                Q(street__icontains=token)
                | Q(building__icontains=token)
                | Q(house_number__icontains=token)
                | Q(postal_code__icontains=token)
                | Q(city__name__icontains=token)
                | Q(country__name__icontains=token)
            )
        return queryset


class RoomCategoryFilterSet(FilterSet):
    class Meta:
        model = RoomCategory
        fields = {
            "category": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class RoomFilterSet(FilterSet):
    class Meta:
        model = Room
        fields = {
            "category__category": ["exact", "contains"],
            "namespace__uri": ["exact", "contains"],
            "name": ["exact", "contains"],
            "number": ["exact", "contains"],
            "floor": ["exact", "contains"],
            "phone_number": ["exact", "contains"],
            "area": ["exact", "contains"],
            "max_people": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class LocationFilterSet(FilterSet):
    class Meta:
        model = Location
        fields = {
            "namespace__uri": ["exact", "contains"],
            "name": ["exact", "contains"],
            "barcode": ["exact", "contains"],
            "iri": ["exact", "contains"],
            "description": ["exact", "contains"],
        }


class LARASyncServerFilterSet(FilterSet):
    class Meta:
        model = LARASyncServer
        fields = {
            "url": ["exact", "contains"],
            "description": ["exact", "contains"],
        }
