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

"""
from django.core.exceptions import ObjectDoesNotExist

from api.utils.serializer.v1.serializer import DeductableAPISerializerV1Mixin, AbstractModelAPISerializerV1
from compensation.models import EcoAccountDeduction, EcoAccount
from intervention.models import Intervention
from konova.utils.message_templates import DATA_UNSHARED


class DeductionAPISerializerV1(AbstractModelAPISerializerV1,
                               DeductableAPISerializerV1Mixin):
    model = EcoAccountDeduction

    def prepare_lookup(self, _id, user):
        """ Updates lookup dict for db fetching

        Args:
            _id (str): The object's id
            user (User): The user requesting for

        Returns:

        """
        super().prepare_lookup(_id, user)
        del self.lookup["users__in"]
        del self.lookup["deleted__isnull"]
        self.lookup["intervention__users__in"] = [user]

    def _model_to_geo_json(self, entry):
        """ Adds the basic data

        Args:
            entry (): The data entry

        Returns:

        """
        return self._single_deduction_to_json(entry)

    def create_model_from_json(self, json_model, user):
        """ Creates a new entry for the model based on the contents of json_model

        Args:
            json_model (dict): The json containing data
            user (User): The API user

        Returns:
            created_id (str): The id of the newly created Intervention entry
        """
        acc_id = json_model["eco_account"]
        intervention_id = json_model["intervention"]
        surface = float(json_model["surface"])
        if surface <= 0:
            raise ValueError("Surface must be > 0 m²")

        acc = EcoAccount.objects.get(
            id=acc_id,
            deleted__isnull=True,
        )
        intervention = Intervention.objects.get(
            id=intervention_id,
            deleted__isnull=True,
        )
        acc_shared = acc.is_shared_with(user)
        intervention_shared = intervention.is_shared_with(user)
        if not acc_shared:
            raise PermissionError(f"Account: {DATA_UNSHARED}")
        if not intervention_shared:
            raise PermissionError(f"Intervention: {DATA_UNSHARED}")

        deduction = self.model.objects.create(
            intervention=intervention,
            account=acc,
            surface=surface
        )
        deduction.intervention.mark_as_edited(user)
        return str(deduction.id)

    def _get_obj_from_db(self, id, user):
        """ Returns the object from database

        Fails if id not found or user does not have shared access

        Args:
            id (str): The object's id
            user (User): The API user

        Returns:

        """
        obj = self.model.objects.get(
            id=id,
        )
        shared_with = obj.intervention.is_shared_with(user)
        if not shared_with:
            raise PermissionError(f"Intervention: {DATA_UNSHARED}")
        return obj

    def update_model_from_json(self, id, json_model, user):
        """ Updates an entry for the model based on the contents of json_model

        Args:
            id (str): The object's id
            json_model (dict): The json containing data
            user (User): The API user

        Returns:
            created_id (str): The id of the newly created Intervention entry
        """
        deduction = self._get_obj_from_db(id, user)

        acc_id = json_model["eco_account"]
        intervention_id = json_model["intervention"]
        surface = float(json_model["surface"])
        if surface <= 0:
            raise ValueError("Surface must be > 0 m²")

        acc = EcoAccount.objects.get(
            id=acc_id,
            deleted__isnull=True,
        )
        intervention = Intervention.objects.get(
            id=intervention_id,
            deleted__isnull=True,
        )
        acc_shared = acc.is_shared_with(user)
        intervention_shared = intervention.is_shared_with(user)
        if not acc_shared:
            raise PermissionError(f"Account: {DATA_UNSHARED}")
        if not intervention_shared:
            raise PermissionError(f"Intervention: {DATA_UNSHARED}")

        deduction.intervention = intervention
        deduction.account = acc
        deduction.surface = surface
        deduction.save()

        deduction.intervention.mark_as_edited(user)

        return str(deduction.id)

    def delete_entry(self, id, user):
        """ Deletes the entry

        Args:
            id (str): The entry's id
            user (User): The API user

        Returns:

        """
        entry = self._get_obj_from_db(id, user)
        entry.intervention.mark_as_edited(user)
        entry.delete()
        try:
            entry.refresh_from_db()
            success = False
        except ObjectDoesNotExist:
            success = True
        return success