"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 15.11.21

"""
import shutil

from django.contrib import messages
from django.db import models
from django.db.models import QuerySet
from django.http import HttpRequest
from django.urls import reverse

from compensation.models import AbstractCompensation, PikMixin
from ema.managers import EmaManager
from ema.utils.quality import EmaQualityChecker
from konova.models import AbstractDocument, generate_document_file_upload_path, RecordableObjectMixin, ShareableObjectMixin
from konova.utils.message_templates import DATA_UNSHARED_EXPLANATION, DOCUMENT_REMOVED_TEMPLATE


class Ema(AbstractCompensation, ShareableObjectMixin, RecordableObjectMixin, PikMixin):
    """
    EMA = Ersatzzahlungsmaßnahme
    (compensation actions from payments)

    Until 2015 the EMA was the data object to keep track of any compensation, which has been funded by payments
    previously paid. In 2015 another organization got in charge of this, which led to the creation of the data object
    MAE (which is basically the same, just renamed in their system) to differ between the 'old' payment funded ones and
    the new. For historical reasons, we need to keep EMAs in our system, since there are still entries done to this day,
    which have been performed somewhere before 2015 and therefore needs to be entered.
    Further information:
    https://snu.rlp.de/de/foerderungen/massnahmen-aus-ersatzzahlungen/uebersicht-mae/

    EMA therefore holds data like a compensation: actions, before-/after-states, deadlines, ...

    """
    objects = EmaManager()

    def __str__(self):
        return "{}".format(self.identifier)

    def save(self, *args, **kwargs):
        if self.identifier is None or len(self.identifier) == 0:
            # Create new identifier
            new_id = self.generate_new_identifier()
            while Ema.objects.filter(identifier=new_id).exists():
                new_id = self.generate_new_identifier()
            self.identifier = new_id
        super().save(*args, **kwargs)

    def quality_check(self) -> EmaQualityChecker:
        """ Quality check

        Returns:
            ret_msgs (EmaQualityChecker): Holds validity error messages
        """
        checker = EmaQualityChecker(self)
        checker.run_check()
        return checker

    def get_documents(self) -> QuerySet:
        """ Getter for all documents of an EMA

        Returns:
            docs (QuerySet): The queryset of all documents
        """
        docs = EmaDocument.objects.filter(
            instance=self
        )
        return docs

    def set_status_messages(self, request: HttpRequest):
        """ Setter for different information that need to be rendered

        Adds messages to the given HttpRequest

        Args:
            request (HttpRequest): The incoming request

        Returns:
            request (HttpRequest): The modified request
        """
        if not self.is_shared_with(request.user):
            messages.info(request, DATA_UNSHARED_EXPLANATION)
        self.set_geometry_conflict_message(request)
        return request

    def is_ready_for_publish(self) -> bool:
        """ Checks whether the data passes all constraints for being publishable

        Returns:
            is_ready (bool) : True|False
        """
        is_recorded = self.recorded is not None
        is_ready = is_recorded
        return is_ready

    def get_share_link(self):
        """ Returns the share url for the object

        Returns:

        """
        return reverse("ema:share-token", args=(self.id, self.access_token))


class EmaDocument(AbstractDocument):
    """
    Specializes document upload for ema with certain path
    """
    instance = models.ForeignKey(
        Ema,
        on_delete=models.CASCADE,
        related_name="documents",
    )
    file = models.FileField(
        upload_to=generate_document_file_upload_path,
        max_length=1000,
    )

    def delete(self, user=None, *args, **kwargs):
        """
        Custom delete functionality for EcoAccountDocuments.
        Removes the folder from the file system if there are no further documents for this entry.

        Args:
            *args ():
            **kwargs ():

        Returns:

        """
        ema_docs = self.instance.get_documents()

        folder_path = None
        if ema_docs.count() == 1:
            # The only file left for this EMA is the one which is currently processed and will be deleted
            # Make sure that the compensation folder itself is deleted as well, not only the file
            # Therefore take the folder path from the file path
            folder_path = self.file.path.split("/")[:-1]
            folder_path = "/".join(folder_path)

        if user:
            self.instance.mark_as_edited(user, edit_comment=DOCUMENT_REMOVED_TEMPLATE.format(self.title))

        # Remove the file itself
        super().delete(*args, **kwargs)

        # If a folder path has been set, we need to delete the whole folder!
        if folder_path is not None:
            try:
                shutil.rmtree(folder_path)
            except FileNotFoundError:
                # Folder seems to be missing already...
                pass
