from django.contrib import admin
from django.contrib.gis import geos
from leaflet.admin import LeafletGeoAdmin, LeafletGeoAdminMixin
from .models import Lau1
from .models import Nuts3
from .models import Airport
from .models import Road
from .models import PublicTransportStop
from .models import RailwayStation
from django.urls import reverse
from django.utils.translation import ugettext_lazy as _
import nested_admin
import uuid
import json


class AirportAdmin(LeafletGeoAdmin):
    default_zoom = 7
    default_lon = 1730000
    default_lat = 6430000
    #readonly_fields = ("code", "name",)

class RoadAdmin(LeafletGeoAdmin):
    default_zoom = 7
    default_lon = 1730000
    default_lat = 6430000
    #readonly_fields = ("code", "name",)

class RailwayStationAdmin(LeafletGeoAdmin):
    default_zoom = 7
    default_lon = 1730000
    default_lat = 6430000
    #readonly_fields = ("code", "name",)

class PublicTransportStopAdmin(LeafletGeoAdmin):
    default_zoom = 7
    default_lon = 1730000
    default_lat = 6430000
    #readonly_fields = ("code", "name",)


class LAU1Admin(LeafletGeoAdmin):
    default_zoom = 7
    default_lon = 1730000
    default_lat = 6430000
    #readonly_fields = ("code", "name",)


class NUTS3Admin(LeafletGeoAdmin):
    default_zoom = 7
    default_lon = 1730000
    default_lat = 6430000

    #readonly_fields = ("code", "name",)


class NUTS3AdminInline(LeafletGeoAdminMixin, admin.StackedInline):
    model = Nuts3


class LAU1AdminInline(LeafletGeoAdminMixin, admin.StackedInline):
    model = Lau1


class NUTS3Filter(admin.SimpleListFilter):
    """Filter for admin interface of NUTS3 regions (Kraje)
    """
    title = _('NUTS3 regions')
    parameter_name = 'nuts3#'

    def lookups(self, request, model_admin):
        nuts3 = Nuts3.objects.all()
        return (
            (obj.id, obj.name) for obj in nuts3
        )

    def queryset(self, request, queryset):
        val = self.value()
        if val:
            nuts3 = Nuts3.objects.get(pk=val)
            results = queryset.filter(
                location__geometry__intersects=nuts3.geometry)
        else:
            results = queryset

        return results


class ArealFieldAdmin(nested_admin.NestedModelAdmin):
    geojson_attributes = []

    def get_place(self, obj):
        if hasattr(obj.location, "address") and \
           obj.location.address is not None:
            return obj.location.address.city
        else:
            return ", ".join(
                [l.__str__() for l in Nuts3.objects.filter(
                    geometry__intersects=obj.location.geometry)])

    def get_search_results(self, request, queryset, search_term):
        """Add NUTS3 (by name) search and area size search (using `<>` operator)
        """

        result, use_distinct = super(
            ArealFieldAdmin, self).get_search_results(
                request, queryset, search_term)
        if search_term:
            if len(result) == 0 or len(result) == len(queryset):
                    result = self._search_lay1_nuts3_by_name(
                        queryset, search_term)
            if len(result) == 0 or len(result) == len(queryset):
                result = self._search_area(queryset, search_term)

        return (result, use_distinct)

    def _search_lay1_nuts3_by_name(self, queryset, search_term):
        """Search NUTS3 (kraje) and LAU1 (okresy) region according to name
        """

        filtered = queryset.none()
        for cls in (Lau1, Nuts3):
            objs = cls.objects.filter(name__startswith=search_term)
            for o in objs:
                objects = queryset.filter(
                    location__geometry__intersects=o.geometry)
                filtered |= objects
        return filtered

    def _search_area(self, queryset, search_term):
        """Search all features, where MIN < area.total < MAX
        """

        filtered = queryset.none()
        if search_term.find("<>") > -1:
            area_min, area_max = [float(x) for x in search_term.split("<>")]
            filtered = queryset.filter(
                    areal__area__total__gte=area_min,
                    areal__area__total__lte=area_max)
        return filtered

    def changelist_view(self, request, extra_context=None):
        """Adjust change list view
        add GeoJSON encoded data for the queryset
        """

        extra_context = extra_context or {}
        response = super().changelist_view(
            request, extra_context=extra_context,
        )
        if hasattr(response, "context_data"):
            filtered_query_set = response.context_data["cl"].queryset

            extra_context['objects_data'] = \
                json.dumps(self.as_geojson(filtered_query_set))

            response.context_data.update(extra_context)
        return response

    def as_geojson(self, queryset):
        if self.geojson_attributes:
            attributes = self.geojson_attributes
        else:
            attributes = []

        data = {
            "type": "FeatureCollection",
            "features": []
        }
        for obj in queryset:

            geom = None

            if hasattr(obj, "location_set"):
                multipoint = geos.MultiPoint(
                    [loc.address.coordinates for loc in obj.location_set.all()])
                geom = multipoint.centroid
            elif hasattr(obj, "location"):

                geom = obj.location.geometry.centroid

            elif hasattr(obj, "geom"):
                geom = obj.geom

            elif hasattr(obj, "address"):
                geom = obj.address.coordinates

            if geom:
                title = None
                if hasattr(obj, "title"):
                    title = obj.title
                elif hasattr(obj, "name"):
                    title = obj.name

                if type(obj.pk) == uuid.UUID:
                    id = str(obj.pk)
                else:
                    id = obj.pk

                feature = {
                    "type": "Feature",
                    "properties": {
                        "name": title,
                        "object_url":
                            reverse('admin:{}_{}_change'.format(
                                obj._meta.app_label,
                                obj._meta.model_name), args=(obj.pk,)),
                    },
                    "geometry": json.loads(geom.json),
                    "id": id
                }

                for attribute in attributes:
                    if hasattr(obj, attribute):
                        value = getattr(obj, attribute.__str__())
                        if type(value) == uuid.UUID:
                            feature[attribute] = str(value)
                        else:
                            feature[attribute] = value


                #print(feature)
                data["features"].append(feature)

        return data


# Register your models here.
admin.site.register(Lau1, LAU1Admin)
admin.site.register(Nuts3, NUTS3Admin)
admin.site.register(Road, RoadAdmin)
admin.site.register(PublicTransportStop, PublicTransportStopAdmin)
admin.site.register(RailwayStation, RailwayStationAdmin)
admin.site.register(Airport, AirportAdmin)

[((229, 0, 229, 36), 'django.contrib.admin.site.register', 'admin.site.register', ({(229, 20, 229, 24): 'Lau1', (229, 26, 229, 35): 'LAU1Admin'}, {}), '(Lau1, LAU1Admin)', False, 'from django.contrib import admin\n'), ((230, 0, 230, 38), 'django.contrib.admin.site.register', 'admin.site.register', ({(230, 20, 230, 25): 'Nuts3', (230, 27, 230, 37): 'NUTS3Admin'}, {}), '(Nuts3, NUTS3Admin)', False, 'from django.contrib import admin\n'), ((231, 0, 231, 36), 'django.contrib.admin.site.register', 'admin.site.register', ({(231, 20, 231, 24): 'Road', (231, 26, 231, 35): 'RoadAdmin'}, {}), '(Road, RoadAdmin)', False, 'from django.contrib import admin\n'), ((232, 0, 232, 66), 'django.contrib.admin.site.register', 'admin.site.register', ({(232, 20, 232, 39): 'PublicTransportStop', (232, 41, 232, 65): 'PublicTransportStopAdmin'}, {}), '(PublicTransportStop, PublicTransportStopAdmin)', False, 'from django.contrib import admin\n'), ((233, 0, 233, 56), 'django.contrib.admin.site.register', 'admin.site.register', ({(233, 20, 233, 34): 'RailwayStation', (233, 36, 233, 55): 'RailwayStationAdmin'}, {}), '(RailwayStation, RailwayStationAdmin)', False, 'from django.contrib import admin\n'), ((234, 0, 234, 42), 'django.contrib.admin.site.register', 'admin.site.register', ({(234, 20, 234, 27): 'Airport', (234, 29, 234, 41): 'AirportAdmin'}, {}), '(Airport, AirportAdmin)', False, 'from django.contrib import admin\n'), ((68, 12, 68, 30), 'django.utils.translation.ugettext_lazy', '_', ({(68, 14, 68, 29): '"""NUTS3 regions"""'}, {}), "('NUTS3 regions')", True, 'from django.utils.translation import ugettext_lazy as _\n'), ((209, 32, 209, 53), 'json.loads', 'json.loads', ({(209, 43, 209, 52): 'geom.json'}, {}), '(geom.json)', False, 'import json\n')]