"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 19.08.22

"""
from django.contrib.gis.geos import MultiPolygon
from django.http import HttpResponse, HttpRequest
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from django.utils import timezone
from django.views import View

from konova.models import Geometry
from konova.settings import GEOM_THRESHOLD_RECALCULATION_SECONDS
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
from konova.tasks import celery_update_parcels


class GeomParcelsView(View):

    def get(self, request: HttpRequest, id: str):
        """ Getter for HTMX

        Returns all parcels of the requested geometry rendered into a simple HTML table

        Args:
            request (HttpRequest): The incoming request
            id (str): The geometry's id

        Returns:
            A rendered piece of HTML
        """
        template = "konova/includes/parcels/parcel_table_frame.html"

        geom = get_object_or_404(Geometry, id=id)
        geos_geom = geom.geom or MultiPolygon(srid=DEFAULT_SRID_RLP)
        geometry_exists = not geos_geom.empty and geos_geom.area > 0
        geom_parcel_update_started = geom.parcel_update_start is not None
        geom_parcel_update_finished = geom.parcel_update_end is not None

        parcels = geom.get_underlying_parcels()
        parcels_are_available = len(parcels) > 0

        waiting_too_long = self._check_waiting_too_long(geom)

        if geometry_exists and not parcels_are_available and waiting_too_long:
            # Trigger calculation again - process may have failed silently
            celery_update_parcels.delay(geom.id)
            parcels_are_currently_calculated = True
        else:
            parcels_are_currently_calculated = (
                    geometry_exists and
                    not parcels_are_available and
                    geom_parcel_update_started and
                    not geom_parcel_update_finished
            )

        if parcels_are_currently_calculated:
            # Parcels are being calculated right now. Change the status code, so polling stays active for fetching
            # results after the calculation
            status_code = 200
        else:
            # HTTP code 286 states that the HTMX should stop polling for updates
            # https://htmx.org/docs/#polling
            status_code = 286

        if parcels_are_available or not geometry_exists:
            # Default case: Parcels are calculated or there is no geometry at all
            # (so there will be no parcels to expect)
            municipals = geom.get_underlying_municipals(parcels)

            rpp = 100
            num_all_parcels = parcels.count()
            parcels = parcels[:rpp]
            next_page = 1
            if len(parcels) < rpp:
                next_page = None

            context = {
                "num_parcels": num_all_parcels,
                "parcels": parcels,
                "municipals": municipals,
                "geom_id": str(id),
                "next_page": next_page,
            }
            html = render_to_string(template, context, request)
            return HttpResponse(html, status=status_code)
        else:
            return HttpResponse(None, status=404)

    def _check_waiting_too_long(self, geom: Geometry):
        """ Check whether the client is waiting too long for a parcel calculation result

        Depending on the geometry's modified attribute

        """
        # Scale time to wait longer with increasing geometry complexity
        complexity_factor = geom.complexity_factor + 1
        wait_for_seconds = int(GEOM_THRESHOLD_RECALCULATION_SECONDS * complexity_factor)
        try:
            pcs_diff = (timezone.now() - geom.parcel_update_start).seconds
        except TypeError:
            pcs_diff = wait_for_seconds

        waiting_too_long = (pcs_diff >= wait_for_seconds)
        return waiting_too_long


class GeomParcelsContentView(View):

    def get(self, request: HttpRequest, id: str, page: int):
        """ Getter for infinite scroll of HTMX

        Returns parcels of a specific page/slice of the found parcel set.
        Implementation of infinite scroll htmx example: https://htmx.org/examples/infinite-scroll/

        Args:
            request (HttpRequest): The incoming request
            id (str): The geometry's id
            page (int): The requested page number

        Returns:
            A rendered piece of HTML
        """
        if page < 0:
            raise AssertionError("Parcel page can not be negative")

        # HTTP code 286 states that the HTMX should stop polling for updates
        # https://htmx.org/docs/#polling
        status_code = 286
        template = "konova/includes/parcels/parcel_table_content.html"
        geom = get_object_or_404(Geometry, id=id)
        parcels = geom.get_underlying_parcels()

        parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr")
        rpp = 100
        from_p = rpp * (page-1)
        to_p = rpp * (page)
        next_page = page + 1
        parcels = parcels[from_p:to_p]
        if len(parcels) < rpp:
            next_page = None

        context = {
            "parcels": parcels,
            "geom_id": str(id),
            "next_page": next_page,
        }
        html = render_to_string(template, context, request)
        return HttpResponse(html, status=status_code)
