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

"""
from dal import autocomplete
from django import forms

from konova.forms.base_form import BaseForm
from konova.utils import validators
from konova.utils.message_templates import EDITED_GENERAL_DATA
from user.models import User
from django.db import transaction
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _

from codelist.models import KonovaCode
from codelist.settings import CODELIST_PROCESS_TYPE_ID, CODELIST_LAW_ID, \
    CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_HANDLER_ID
from intervention.inputs import GenerateInput
from intervention.models import Intervention, Legal, Responsibility, Handler
from konova.forms.geometry_form import SimpleGeomForm
from user.models import UserActionLogEntry


class NewInterventionForm(BaseForm):
    identifier = forms.CharField(
        label=_("Identifier"),
        label_suffix="",
        max_length=255,
        help_text=_("Generated automatically - not editable"),
        widget=GenerateInput(
            attrs={
                "class": "form-control",
                "url": reverse_lazy("intervention:new-id"),
                "readonly": True,
            }
        )
    )
    title = forms.CharField(
        label=_("Title"),
        label_suffix="",
        help_text=_("An explanatory name"),
        max_length=255,
        widget=forms.TextInput(
            attrs={
                "placeholder": _("Construction XY; Location ABC"),
                "class": "form-control",
            }
        )
    )
    type = forms.ModelChoiceField(
        label=_("Process type"),
        label_suffix="",
        help_text=_(""),
        required=False,
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_PROCESS_TYPE_ID],
        ),
        widget=autocomplete.ModelSelect2(
            url="codelist:process-type-autocomplete",
            attrs={
                "data-placeholder": _("Click for selection"),
            }
        ),
    )
    laws = forms.ModelMultipleChoiceField(
        label=_("Law"),
        label_suffix="",
        help_text=_("Multiple selection possible"),
        required=False,
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_LAW_ID],
        ),
        widget=autocomplete.ModelSelect2Multiple(
            url="codelist:law-autocomplete",
            attrs={
                "data-placeholder": _("Click for selection"),
            }
        ),
    )
    registration_office = forms.ModelChoiceField(
        label=_("Registration office"),
        label_suffix="",
        required=False,
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID],
        ),
        widget=autocomplete.ModelSelect2(
            url="codelist:registration-office-autocomplete",
            attrs={
                "data-placeholder": _("Click for selection"),
            }
        ),
    )
    conservation_office = forms.ModelChoiceField(
        label=_("Conservation office"),
        label_suffix="",
        required=False,
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
        ),
        widget=autocomplete.ModelSelect2(
            url="codelist:conservation-office-autocomplete",
            attrs={
                "data-placeholder": _("Click for selection"),
            }
        ),
    )
    registration_file_number = forms.CharField(
        label=_("Registration office file number"),
        label_suffix="",
        max_length=255,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": _("ZB-123/ABC.456"),
                "class": "form-control",
            }
        )
    )
    conservation_file_number = forms.CharField(
        label=_("Conservation office file number"),
        label_suffix="",
        max_length=255,
        required=False,
        widget=forms.TextInput(
            attrs={
                "placeholder": _("ETS-123/ABC.456"),
                "class": "form-control",
            }
        )
    )
    handler_type = forms.ModelChoiceField(
        label=_("Intervention handler type"),
        label_suffix="",
        help_text=_("What type of handler is responsible for the intervention?"),
        required=False,
        queryset=KonovaCode.objects.filter(
            is_archived=False,
            is_leaf=True,
            code_lists__in=[CODELIST_HANDLER_ID],
        ),
        widget=autocomplete.ModelSelect2(
            url="codelist:handler-autocomplete",
            attrs={
                "data-placeholder": _("Click for selection"),
            }
        ),
    )
    handler_detail = forms.CharField(
        label=_("Intervention handler detail"),
        label_suffix="",
        max_length=255,
        required=False,
        help_text=_("Detail input on the handler"),
        widget=forms.TextInput(
            attrs={
                "placeholder": _("Company Mustermann"),
                "class": "form-control",
            }
        )
    )

    registration_date = forms.DateField(
        label=_("Registration date"),
        label_suffix=_(""),
        required=False,
        validators=[validators.reasonable_date],
        widget=forms.DateInput(
            attrs={
                "type": "date",
                "class": "form-control",
            },
            format="%d.%m.%Y"
        )
    )
    binding_date = forms.DateField(
        label=_("Binding on"),
        label_suffix=_(""),
        required=False,
        validators=[validators.reasonable_date],
        widget=forms.DateInput(
            attrs={
                "type": "date",
                "class": "form-control",
            },
            format="%d.%m.%Y"
        )
    )
    comment = forms.CharField(
        label_suffix="",
        label=_("Comment"),
        required=False,
        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 intervention")
        self.action_url = reverse("intervention:new")
        self.cancel_redirect = reverse("intervention:index")

        tmp_intervention = Intervention()
        identifier = tmp_intervention.generate_new_identifier()
        self.initialize_form_field("identifier", identifier)

    def is_valid(self):
        super_valid_result = super().is_valid()
        return super_valid_result

    def save(self, user: User, geom_form: SimpleGeomForm):
        with transaction.atomic():
            # Fetch data from cleaned POST values
            identifier = self.cleaned_data.get("identifier", None)
            title = self.cleaned_data.get("title", None)
            _type = self.cleaned_data.get("type", None)
            laws = self.cleaned_data.get("laws", None)
            handler_type = self.cleaned_data.get("handler_type", None)
            handler_detail = self.cleaned_data.get("handler_detail", None)
            registration_office = self.cleaned_data.get("registration_office", None)
            conservation_office = self.cleaned_data.get("conservation_office", None)
            conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
            registration_file_number = self.cleaned_data.get("registration_file_number", None)
            binding_date = self.cleaned_data.get("binding_date", None)
            registration_date = self.cleaned_data.get("registration_date", None)
            comment = self.cleaned_data.get("comment", None)

            # Create log entry
            action = UserActionLogEntry.get_created_action(user)

            # Create legal data object (without M2M laws first)
            legal_data = Legal.objects.create(
                registration_date=registration_date,
                binding_date=binding_date,
                process_type=_type,
            )
            # Then add the M2M laws to the object
            legal_data.laws.set(laws)

            handler = Handler.objects.create(
                type=handler_type,
                detail=handler_detail
            )
            # Create responsible data object
            responsibility_data = Responsibility.objects.create(
                registration_office=registration_office,
                conservation_office=conservation_office,
                registration_file_number=registration_file_number,
                conservation_file_number=conservation_file_number,
                handler=handler,
            )

            # Finally create main object, holding the other objects
            intervention = Intervention.objects.create(
                identifier=identifier,
                title=title,
                responsible=responsibility_data,
                legal=legal_data,
                created=action,
                modified=action,
                comment=comment,
            )

            # Add the log entry to the main objects log list
            intervention.log.add(action)

            # Add the performing user as the first user having access to the data
            intervention.share_with_user(user)

        # Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
        geometry = geom_form.save(action)
        intervention.geometry = geometry
        intervention.save()

        return intervention


class EditInterventionForm(NewInterventionForm):
    """ Subclasses NewInterventionForm

    Simply adds initializing of a provided self.instance object into the form fields

    """
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self.instance is not None:
            self.action_url = reverse("intervention:edit", args=(self.instance.id,))
        self.cancel_redirect = reverse("intervention:detail", args=(self.instance.id,))
        self.form_title = _("Edit intervention")
        self.form_caption = ""

        reg_date = self.instance.legal.registration_date
        bind_date = self.instance.legal.binding_date
        if reg_date is not None:
            reg_date = reg_date.isoformat()
        if bind_date is not None:
            bind_date = bind_date.isoformat()

        # Initialize form data
        form_data = {
            "identifier": self.instance.identifier,
            "title": self.instance.title,
            "type": self.instance.legal.process_type,
            "laws": list(self.instance.legal.laws.values_list("id", flat=True)),
            "handler_type": self.instance.responsible.handler.type,
            "handler_detail": self.instance.responsible.handler.detail,
            "registration_office": self.instance.responsible.registration_office,
            "registration_file_number": self.instance.responsible.registration_file_number,
            "conservation_office": self.instance.responsible.conservation_office,
            "conservation_file_number": self.instance.responsible.conservation_file_number,
            "registration_date": reg_date,
            "binding_date": bind_date,
            "comment": self.instance.comment,
        }
        disabled_fields = []
        self.load_initial_data(
            form_data,
            disabled_fields
        )

    def save(self, user: User, geom_form: SimpleGeomForm):
        """ Overwrite instance with new form data

        Args:
            user ():

        Returns:

        """
        with transaction.atomic():
            title = self.cleaned_data.get("title", None)
            process_type = self.cleaned_data.get("type", None)
            laws = self.cleaned_data.get("laws", None)
            handler_type = self.cleaned_data.get("handler_type", None)
            handler_detail = self.cleaned_data.get("handler_detail", None)
            registration_office = self.cleaned_data.get("registration_office", None)
            registration_file_number = self.cleaned_data.get("registration_file_number", None)
            conservation_office = self.cleaned_data.get("conservation_office", None)
            conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
            registration_date = self.cleaned_data.get("registration_date", None)
            binding_date = self.cleaned_data.get("binding_date", None)
            comment = self.cleaned_data.get("comment", None)

            self.instance.legal.process_type = process_type
            self.instance.legal.registration_date = registration_date
            self.instance.legal.binding_date = binding_date
            self.instance.legal.laws.set(laws)
            self.instance.legal.save()

            self.instance.responsible.handler.type = handler_type
            self.instance.responsible.handler.detail = handler_detail
            self.instance.responsible.handler.save()

            self.instance.responsible.registration_office = registration_office
            self.instance.responsible.registration_file_number = registration_file_number
            self.instance.responsible.conservation_office = conservation_office
            self.instance.responsible.conservation_file_number = conservation_file_number
            self.instance.responsible.save()

            user_action = self.instance.mark_as_edited(user, edit_comment=EDITED_GENERAL_DATA)

            self.instance.log.add(user_action)

            self.instance.title = title
            self.instance.comment = comment
            self.instance.modified = user_action
            self.instance.save()

        # Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
        geometry = geom_form.save(user_action)
        self.instance.geometry = geometry
        self.instance.save()
        self.instance.send_data_to_egon()

        return self.instance