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

"""
from bootstrap_modal_forms.utils import is_ajax
from dal import autocomplete
from django import forms
from django.contrib import messages
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import render
from django.utils.translation import pgettext_lazy as _con, gettext_lazy as _

from codelist.models import KonovaCode
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID, \
    CODELIST_COMPENSATION_ACTION_DETAIL_ID
from compensation.models import CompensationDocument, EcoAccountDocument
from konova.contexts import BaseContext
from konova.forms import BaseModalForm, NewDocumentForm
from konova.models import DeadlineType
from konova.utils.message_templates import FORM_INVALID, ADDED_COMPENSATION_STATE, ADDED_DEADLINE, \
    ADDED_COMPENSATION_ACTION, PAYMENT_ADDED


class NewPaymentForm(BaseModalForm):
    """ Form handling payment related input

    """
    amount = forms.DecimalField(
        min_value=0.00,
        decimal_places=2,
        label=_con("money", "Amount"),  # contextual translation
        label_suffix=_(""),
        help_text=_("in Euro"),
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "placeholder": "0,00",
            }
        )
    )
    due = forms.DateField(
        label=_("Due on"),
        label_suffix=_(""),
        required=False,
        help_text=_("Due on which date"),
        widget=forms.DateInput(
            attrs={
                "type": "date",
                "data-provide": "datepicker",
                "class": "form-control",
            },
            format="%d.%m.%Y"
        )
    )
    comment = forms.CharField(
        max_length=200,
        required=False,
        label=_("Comment"),
        label_suffix=_(""),
        help_text=_("Additional comment, maximum {} letters").format(200),
        widget=forms.Textarea(
            attrs={
                "rows": 5,
                "class": "form-control"
            }
        )
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.intervention = self.instance
        self.form_title = _("Payment")
        self.form_caption = _("Add a payment for intervention '{}'").format(self.intervention.title)

    def is_valid(self):
        """
        Checks on form validity.

        For this form we need to make sure that a date or a comment is set.
        If both are missing, the user needs to enter at least an explanation why
        there is no date to be entered.

        Returns:
            is_valid (bool): True if valid, False otherwise
        """
        super_valid = super().is_valid()
        date = self.cleaned_data["due"]
        comment = self.cleaned_data["comment"] or None
        if not date and not comment:
            # At least one needs to be set!
            self.add_error(
                "comment",
                _("If there is no date you can enter, please explain why.")
            )
            return False
        return super_valid

    def save(self):
        pay = self.instance.add_payment(self)
        self.instance.mark_as_edited(self.user, self.request, edit_comment=PAYMENT_ADDED)
        return pay


class NewStateModalForm(BaseModalForm):
    """ Form handling state related input

    Compensation states refer to 'before' and 'after' states of a compensated surface. Basically it means:
    What has been on this area before changes/compensations have been applied and what will be the result ('after')?

    """
    biotope_type = forms.ModelChoiceField(
        label=_("Biotope Type"),
        label_suffix="",
        required=True,
        help_text=_("Select the biotope type"),
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_BIOTOPES_ID],
        ),
        widget=autocomplete.ModelSelect2(
            url="codes-biotope-autocomplete",
            attrs={
                "data-placeholder": _("Biotope Type"),
            }
        ),
    )
    biotope_extra = forms.ModelMultipleChoiceField(
        label=_("Biotope additional type"),
        label_suffix="",
        required=False,
        help_text=_("Select an additional biotope type"),
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_ID],
        ),
        widget=autocomplete.ModelSelect2Multiple(
            url="codes-biotope-extra-type-autocomplete",
            attrs={
                "data-placeholder": _("Biotope additional type"),
            }
        ),
    )
    surface = forms.DecimalField(
        min_value=0.00,
        decimal_places=2,
        label=_("Surface"),
        label_suffix="",
        required=True,
        help_text=_("in m²"),
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "placeholder": "0,00"
            }
        )
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.form_title = _("New state")
        self.form_caption = _("Insert data for the new state")

    def save(self, is_before_state: bool = False):
        state = self.instance.add_state(self, is_before_state)
        self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_STATE)
        return state

    def process_request(self, request: HttpRequest, msg_success: str = _("Object removed"), msg_error: str = FORM_INVALID, redirect_url: str = None):
        """ Generic processing of request

        Wraps the request processing logic, so we don't need the same code everywhere a RemoveModalForm is being used

        +++
        The generic method from super class can not be used, since we need to do some request parameter check in here.
        +++

        Args:
            request (HttpRequest): The incoming request
            msg_success (str): The message in case of successful removing
            msg_error (str): The message in case of an error

        Returns:

        """
        redirect_url = redirect_url if redirect_url is not None else request.META.get("HTTP_REFERER", "home")
        template = self.template
        if request.method == "POST":
            if self.is_valid():
                # Modal forms send one POST for checking on data validity. This can be used to return possible errors
                # on the form. A second POST (if no errors occured) is sent afterwards and needs to process the
                # saving/commiting of the data to the database. is_ajax() performs this check. The first request is
                # an ajax call, the second is a regular form POST.
                if not is_ajax(request.META):
                    is_before_state = bool(request.GET.get("before", False))
                    self.save(is_before_state=is_before_state)
                    messages.success(
                        request,
                        msg_success
                    )
                return HttpResponseRedirect(redirect_url)
            else:
                context = {
                    "form": self,
                }
                context = BaseContext(request, context).context
                return render(request, template, context)
        elif request.method == "GET":
            context = {
                "form": self,
            }
            context = BaseContext(request, context).context
            return render(request, template, context)
        else:
            raise NotImplementedError


class NewDeadlineModalForm(BaseModalForm):
    """ Form handling deadline related input

    """
    type = forms.ChoiceField(
        label=_("Deadline Type"),
        label_suffix="",
        required=True,
        help_text=_("Select the deadline type"),
        choices=DeadlineType.choices,
        widget=forms.Select(
            attrs={
                "class": "form-control"
            }
        )
    )
    date = forms.DateField(
        label=_("Date"),
        label_suffix="",
        required=True,
        help_text=_("Select date"),
        widget=forms.DateInput(
            attrs={
                "type": "date",
                "data-provide": "datepicker",
                "class": "form-control",
            },
            format="%d.%m.%Y"
        )
    )
    comment = forms.CharField(
        required=False,
        max_length=200,
        label=_("Comment"),
        label_suffix=_(""),
        help_text=_("Additional comment, maximum {} letters").format(200),
        widget=forms.Textarea(
            attrs={
                "cols": 30,
                "rows": 5,
                "class": "form-control",
            }
        )
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.form_title = _("New deadline")
        self.form_caption = _("Insert data for the new deadline")

    def save(self):
        deadline = self.instance.add_deadline(self)
        self.instance.mark_as_edited(self.user, self.request, ADDED_DEADLINE)
        return deadline


class NewActionModalForm(BaseModalForm):
    """ Form handling action related input

    Compensation actions are the actions performed on the area, which shall be compensated. Actions will change the
    surface of the area, the biotopes, and have an environmental impact. With actions the before-after states can change
    (not in the process logic in Konova, but in the real world).

    """
    from compensation.models import UnitChoices
    action_type = forms.ModelChoiceField(
        label=_("Action Type"),
        label_suffix="",
        required=True,
        help_text=_("Select the action type"),
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_COMPENSATION_ACTION_ID],
        ),
        widget=autocomplete.ModelSelect2(
            url="codes-compensation-action-autocomplete",
            attrs={
                "data-placeholder": _("Action"),
            }
        ),
    )
    action_type_details = forms.ModelMultipleChoiceField(
        label=_("Action Type detail"),
        label_suffix="",
        required=False,
        help_text=_("Select the action type detail"),
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_COMPENSATION_ACTION_DETAIL_ID],
        ),
        widget=autocomplete.ModelSelect2Multiple(
            url="codes-compensation-action-detail-autocomplete",
            attrs={
                "data-placeholder": _("Action Type detail"),
            }
        ),
    )
    unit = forms.ChoiceField(
        label=_("Unit"),
        label_suffix="",
        required=True,
        help_text=_("Select the unit"),
        choices=UnitChoices.choices,
        widget=forms.Select(
            attrs={
                "class": "form-control"
            }
        )
    )
    amount = forms.DecimalField(
        label=_("Amount"),
        label_suffix="",
        required=True,
        help_text=_("Insert the amount"),
        decimal_places=2,
        min_value=0.00,
        widget=forms.NumberInput(
            attrs={
                "class": "form-control",
                "placeholder": "0,00",
            }
        )
    )
    comment = forms.CharField(
        required=False,
        label=_("Comment"),
        label_suffix=_(""),
        help_text=_("Additional comment"),
        widget=forms.Textarea(
            attrs={
                "rows": 5,
                "class": "form-control",
            }
        )
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.form_title = _("New action")
        self.form_caption = _("Insert data for the new action")

    def save(self):
        action = self.instance.add_action(self)
        self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_ACTION)
        return action


class NewCompensationDocumentForm(NewDocumentForm):
    document_model = CompensationDocument


class NewEcoAccountDocumentForm(NewDocumentForm):
    document_model = EcoAccountDocument