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

"""
from django.contrib.auth.models import User
from django.contrib.gis.db import models
from django.core.validators import MinValueValidator
from django.utils import timezone
from django.utils.timezone import now

from compensation.settings import COMPENSATION_IDENTIFIER_LENGTH, COMPENSATION_IDENTIFIER_TEMPLATE
from intervention.models import Intervention, ResponsibilityData
from konova.models import BaseObject, BaseResource, Geometry, UuidModel
from konova.utils.generators import generate_random_string
from organisation.models import Organisation


class Payment(BaseResource):
    """
    Holds data on a payment for an intervention (alternative to a classic compensation)
    """
    amount = models.FloatField(validators=[MinValueValidator(limit_value=0.00)])
    due_on = models.DateField(null=True)
    comment = models.CharField(
        max_length=1000,
        null=True,
        blank=True,
        help_text="Refers to german money transfer 'Verwendungszweck'",
    )
    intervention = models.ForeignKey(
        Intervention,
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        related_name='payments'
    )


class CompensationControl(BaseResource):
    """
    Holds data on how a compensation shall be controlled
    """
    deadline = models.ForeignKey("konova.Deadline", on_delete=models.SET_NULL, null=True, blank=True)
    type = models.CharField(max_length=500, null=True, blank=True)
    expected_result = models.CharField(max_length=500, null=True, blank=True, help_text="The expected outcome, that needs to be controlled")
    by_authority = models.ForeignKey(Organisation, null=True, blank=True, on_delete=models.SET_NULL)
    comment = models.TextField()


class CompensationState(models.Model):
    """
    Compensations must define the state of an area before and after the compensation.
    """
    biotope_type = models.CharField(max_length=500, null=True, blank=True)
    surface = models.FloatField()


class CompensationAction(BaseResource):
    """
    Compensations include actions like planting trees, refreshing rivers and so on.
    """
    action_type = models.CharField(max_length=500, null=True, blank=True)
    amount = models.FloatField()
    unit = models.CharField(max_length=100, null=True, blank=True)
    control = models.ForeignKey(CompensationControl, on_delete=models.SET_NULL, null=True, blank=True)


class Compensation(BaseObject):
    """
    The compensation holds information about which actions have to be performed until which date, who is in charge
    of this, which legal authority is the point of contact, and so on.
    """
    responsible = models.OneToOneField(
        ResponsibilityData,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        help_text="Holds data on responsible organizations ('Zulassungsbehörde', 'Eintragungsstelle') and handler",
    )

    before_states = models.ManyToManyField(CompensationState, blank=True, related_name='+', help_text="Refers to 'Ausgangszustand Biotop'")
    after_states = models.ManyToManyField(CompensationState, blank=True, related_name='+', help_text="Refers to 'Zielzustand Biotop'")
    actions = models.ManyToManyField(CompensationAction, help_text="Refers to 'Maßnahmen'")

    deadlines = models.ManyToManyField("konova.Deadline", null=True, blank=True, related_name="+")

    geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL)
    documents = models.ManyToManyField("konova.Document", blank=True)

    # Holds which intervention is simply a newer version of this dataset
    next_version = models.ForeignKey("Compensation", null=True, blank=True, on_delete=models.DO_NOTHING)

    intervention = models.ForeignKey(
        Intervention,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='compensations'
    )

    @staticmethod
    def _generate_new_identifier() -> str:
        """ Generates a new identifier for the intervention object

        Returns:
            str
        """
        curr_month = str(now().month)
        curr_year = str(now().year)
        rand_str = generate_random_string(
            length=COMPENSATION_IDENTIFIER_LENGTH,
            only_numbers=True,
        )
        _str = "{}{}{}".format(curr_month, curr_year, rand_str)
        return COMPENSATION_IDENTIFIER_TEMPLATE.format(_str)

    def delete(self, *args, **kwargs):
        """ Custom delete functionality

        Does not delete from database but sets a timestamp for being deleted on and which user deleted the object

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

        Returns:

        """
        _now = timezone.now()
        _user = kwargs.get("user", None)
        self.deleted_on = _now
        self.deleted_by = _user
        self.save()

    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 Compensation.objects.filter(identifier=new_id).exists():
                new_id = self._generate_new_identifier()
            self.identifier = new_id
        super().save(*args, **kwargs)


class EcoAccount(Compensation):
    """
    An eco account is a kind of 'prepaid' compensation. It can be compared to an account that already has been filled
    with some kind of currency. From this account one is able to 'withdraw' currency for current projects.
    """
    # Users having access on this object
    users = models.ManyToManyField(User)