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

"""
from django.contrib.auth.models import AbstractUser

from django.db import models

from api.models import APIUserToken
from konova.settings import ZB_GROUP, DEFAULT_GROUP, ETS_GROUP
from konova.utils.mailer import Mailer
from user.enums import UserNotificationEnum


class User(AbstractUser):
    notifications = models.ManyToManyField("user.UserNotification", related_name="+", blank=True)
    api_token = models.OneToOneField(
        "api.APIUserToken",
        blank=True,
        null=True,
        help_text="The user's API token",
        on_delete=models.SET_NULL
    )

    def is_notification_setting_set(self, notification_enum: UserNotificationEnum):
        return self.notifications.filter(
            id=notification_enum.value
        ).exists()

    def is_zb_user(self):
        """ Shortcut for checking whether a user is of a special group or not

        Returns:
            bool
        """
        return self.groups.filter(
            name=ZB_GROUP
        ).exists()

    def is_default_user(self):
        """ Shortcut for checking whether a user is of a special group or not

        Returns:
            bool
        """
        return self.groups.filter(
            name=DEFAULT_GROUP
        ).exists()

    def is_ets_user(self):
        """ Shortcut for checking whether a user is of a special group or not

        Returns:
            bool
        """
        return self.groups.filter(
            name=ETS_GROUP
        ).exists()

    def send_mail_shared_access_removed(self, obj_identifier, obj_title, municipals_names):
        """ Sends a mail to the user in case of removed shared access

        Args:
            obj_identifier ():
            obj_title ():
            municipals_names ():

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_ACCESS_REMOVED)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_shared_access_removed(obj_identifier, obj_title, self, municipals_names)

    def send_mail_shared_access_given(self, obj_identifier, obj_title, municipals_names):
        """ Sends a mail to the user in case of given shared access

        Args:
            obj_identifier (str): The entry identifier
            obj_title (str): The entry title
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_ACCESS_GAINED)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_shared_access_given(obj_identifier, obj_title, self, municipals_names)

    def send_mail_shared_data_recorded(self, obj_identifier, obj_title, municipals_names):
        """ Sends a mail to the user in case of shared data has been recorded

        Args:
            obj_identifier (str): The entry identifier
            obj_title (str): The entry title
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_RECORDED)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_shared_data_recorded(obj_identifier, obj_title, self, municipals_names)

    def send_mail_shared_data_unrecorded(self, obj_identifier, obj_title, municipals_names):
        """ Sends a mail to the user in case of shared data has been unrecorded

        Args:
            obj_identifier (str): The entry identifier
            obj_title (str): The entry title
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_RECORDED)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_shared_data_unrecorded(obj_identifier, obj_title, self, municipals_names)

    def send_mail_shared_data_deleted(self, obj_identifier, obj_title, municipals_names):
        """ Sends a mail to the user in case of shared data has been deleted

        Args:
            obj_identifier (str): The entry identifier
            obj_title (str): The entry title
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_DELETED)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_shared_data_deleted(obj_identifier, obj_title, self, municipals_names)

    def send_mail_shared_data_checked(self, obj_identifier, obj_title, municipals_names):
        """ Sends a mail to the user in case of shared data has been deleted

        Args:
            obj_identifier (str): The entry identifier
            obj_title (str): The entry title
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_SHARED_DATA_CHECKED)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_shared_data_checked(obj_identifier, obj_title, self, municipals_names)

    def send_mail_deduction_changed(self, obj_identifier, obj_title, data_changes):
        """ Sends a mail to the user in case of a changed deduction

        Args:
            obj_identifier (str): Identifier of the main object
            obj_title (str): Title of the main object
            data_changes (dict): Contains the old|new changes of the deduction changes

        Returns:

        """
        notification_set = self.is_notification_setting_set(UserNotificationEnum.NOTIFY_ON_DEDUCTION_CHANGES)
        if notification_set:
            mailer = Mailer()
            mailer.send_mail_deduction_changed(obj_identifier, obj_title, self, data_changes)

    def get_API_token(self):
        """ Getter for an API token

        Creates a new one if none exists, yet.

        Returns:
            token (APIUserToken)
        """
        if self.api_token is None:
            token = APIUserToken.objects.create()
            self.api_token = token
            self.save()
        else:
            token = self.api_token
        return token

    @property
    def shared_teams(self):
        """ Wrapper for fetching active teams of this user

        Returns:

        """
        shared_teams = self.teams.filter(
            deleted__isnull=True
        )
        return shared_teams