""" 
More details on the implementation and usage can be found at
https://www.pyscoop.com/django-jsonfield-attributes-in-admin-filter/
"""

from django.contrib import admin
from django.core.exceptions import ImproperlyConfigured


class JSONFieldFilter(admin.SimpleListFilter):
    """
    Base JSONFilter class to use by individual attribute filter classes.
    e.g  data in JSON field
    {
        "name": "Gaurav",
        "company": "pyscoop",
        "address": {
            "city": "Jaipur",
            "country": {"name": "India", "code": "IN"}
        }
    }
    """
    model_json_field_name = None  # name of the json field column in the model
    json_data_property_name = None  # name of one attribute from json data

    def get_child_value_from_json_field_data(self, json_field_data):
        key_list = self.json_data_property_name.split('__')
        for key in key_list:
            if isinstance(json_field_data, dict):
                json_field_data = json_field_data[key]

        return json_field_data

    def lookups(self, request, model_admin):
        """
        Returns a list of tuples.
        The first element in each tuple is the coded value for the option that will appear in the URL query.
        The 2nd element is the human-readable name for the option that will appear in the right sidebar.
        """
        if self.model_json_field_name is None:
            raise ImproperlyConfigured(f'Filter class {self.__class__.__name__} does not specify "model_json_field_name"')

        if self.json_data_property_name is None:
            raise ImproperlyConfigured(f'Filter class {self.__class__.__name__} does not specify "json_data_property_name"')

        field_value_set = set()

        for json_field_data in model_admin.model.objects.values_list(self.model_json_field_name, flat=True):
            field_value_set.add(self.get_child_value_from_json_field_data(json_field_data))

        return [(v, v) for v in field_value_set]

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value provided in the query string & retrievable via `self.value()`
        """
        if self.value():
            json_field_query = {f'{self.model_json_field_name}__{self.json_data_property_name}': self.value()}
            return queryset.filter(**json_field_query)
        else:
            return queryset


class CompanyFilter(JSONFieldFilter):
    model_json_field_name = 'jsonfield'
    json_data_property_name = 'company'  # property/field in json data
    title = 'Company'  # for admin sidebar
    parameter_name = 'js_company'  # Prefixing with `js_` because one might have another column named `company`, will be used in the URL query