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

"""
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _

from konova.sub_settings.django_settings import DEFAULT_FROM_EMAIL, EMAIL_REPLY_TO, SUPPORT_MAIL_RECIPIENT


class Mailer:
    """
    A wrapper for the django internal mailing functionality
    """
    from_mail = None
    to_mail = []
    fail_silently = False

    # Optional. Can be changed using the constructor to authenticate on the smtp server using other credentials
    auth_user = None
    auth_password = None

    def __init__(self, from_mail: str = DEFAULT_FROM_EMAIL, auth_user: str = None, auth_password: str = None, fail_silently: bool = False):
        self.from_mail = from_mail
        self.fail_silently = fail_silently
        self.auth_user = auth_user
        self.auth_password = auth_password

    def send(self, recipient_list: list, subject: str, msg: str):
        """
        Sends a mail with subject and message
        """
        return send_mail(
            subject=subject,
            message=None,
            html_message=msg,
            from_email=self.from_mail,
            recipient_list=recipient_list,
            fail_silently=self.fail_silently,
            auth_user=self.auth_user,
            auth_password=self.auth_password
        )

    def send_mail_shared_access_removed(self, obj_identifier, obj_title, user, municipals_names):
        """ Send a mail if user has no access to the object anymore

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): The object title
            user (User): Related user
            municipals_names (iterable): List of municipals of the entry

        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/sharing/shared_access_removed.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Shared access removed").format(obj_identifier),
            msg
        )

    def send_mail_shared_access_given(self, obj_identifier, obj_title, user, municipals_names):
        """ Send a mail if user just got access to the object

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

        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/sharing/shared_access_given.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Shared access given").format(obj_identifier),
            msg
        )

    def send_mail_shared_access_given_team(self, obj_identifier, obj_title, team, users_to_notify, municipals_names):
        """ Send a mail if a team just got access to the object

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): Title of the main object
            team (Team): Team to be notified
            users_to_notify (QueryDict): Contains the team users which should be notified
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/sharing/shared_access_given_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Shared access given").format(obj_identifier),
            msg
        )

    def send_mail_shared_access_removed_team(self, obj_identifier, obj_title, team, users_to_notify, municipals_names):
        """ Send a mail if a team just lost access to the object

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): Title of the main object
            team (Team): Team to be notified
            users_to_notify (QueryDict): Contains the team users which should be notified
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/sharing/shared_access_removed_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Shared access removed").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_unrecorded_team(self, obj_identifier, obj_title, team, users_to_notify, municipals_names):
        """ Send a mail if data has just been unrecorded

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): Title of the main object
            team (Team): Team to be notified
            users_to_notify (QueryDict): Contains the team users which should be notified
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/recording/shared_data_unrecorded_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Shared data unrecorded").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_recorded_team(self, obj_identifier, obj_title, team, users_to_notify, municipals_names):
        """ Send a mail if data has just been recorded

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): Title of the main object
            team (Team): Team to be notified
            users_to_notify (QueryDict): Contains the team users which should be notified
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/recording/shared_data_recorded_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Shared data recorded").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_checked_team(self, obj_identifier, obj_title, team, users_to_notify, municipals_names):
        """ Send a mail if data has just been checked

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): Title of the main object
            team (Team): Team to be notified
            users_to_notify (QueryDict): Contains the team users which should be notified
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/checking/shared_data_checked_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Shared data checked").format(obj_identifier),
            msg
        )

    def send_mail_deduction_changed_team(self, obj_identifier, obj_title, team, data_changes, users_to_notify):
        """ Send a mail if deduction has been changed

        Args:
            obj_identifier (str): Identifier of the main object
            obj_title (str): Title of the main object
            team (Team): Team to be notified
            data_changes (dict): Contains the old|new changes of the deduction changes
            users_to_notify (QueryDict): Contains the team users which should be notified
        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
            "data_changes": data_changes,
        }
        msg = render_to_string("email/other/deduction_changed_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Deduction changed").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_deleted_team(self, obj_identifier, obj_title, team, users_to_notify, municipals_names):
        """ Send a mail if data has just been deleted

        Args:
            obj_identifier (str): The object identifier
            obj_title (str): The object title
            team (Team): The related team
            users_to_notify (QuerySet): Contains team users who want to be notified
            municipals_names (iterable): List of municipals for the entry

        Returns:

        """
        context = {
            "team": team,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/deleting/shared_data_deleted_team.html", context)
        user_mail_address = users_to_notify.values_list("email", flat=True)
        self.send(
            user_mail_address,
            _("{} - Shared data deleted").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_recorded(self, obj_identifier, obj_title, user, municipals_names):
        """ Send a mail if the user's shared data has just been unrecorded

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

        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/recording/shared_data_recorded.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Shared data recorded").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_unrecorded(self, obj_identifier, obj_title, user, municipals_names):
        """ Send a mail if the user's shared data has just been unrecorded

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

        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/recording/shared_data_unrecorded.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Shared data unrecorded").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_deleted(self, obj_identifier, obj_title, user, municipals_names):
        """ Send a mail if shared data has just been deleted

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

        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/deleting/shared_data_deleted.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Shared data deleted").format(obj_identifier),
            msg
        )

    def send_mail_shared_data_checked(self, obj_identifier, obj_title, user, municipals_names):
        """ Send a mail if shared data just has been checked

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

        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/checking/shared_data_checked.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Shared data checked").format(obj_identifier),
            msg
        )

    def send_mail_deduction_changed(self, obj_identifier, obj_title, user, data_changes):
        """ Send a mail if deduction has been changed

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


        Returns:

        """
        context = {
            "user": user,
            "obj_identifier": obj_identifier,
            "obj_title": obj_title,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
            "data_changes": data_changes,
        }
        msg = render_to_string("email/other/deduction_changed.html", context)
        user_mail_address = [user.email]
        self.send(
            user_mail_address,
            _("{} - Deduction changed").format(obj_identifier),
            msg
        )

    def send_mail_verify_api_token(self, user):
        """ Send a mail if a user creates a new token

        Args:
            user (User): The user, having a new api token

        Returns:

        """
        context = {
            "user": user,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/api/verify_token.html", context)
        user_mail_address = [SUPPORT_MAIL_RECIPIENT]
        self.send(
            user_mail_address,
            _("Request for new API token"),
            msg
        )

    def send_mail_resubmission(self, obj_identifier, resubmission, municipals_names):
        """ Send a resubmission mail for a user

        Args:
            obj_identifier (str): The (resubmitted) object's identifier
            resubmission (Resubmission): The resubmission
            municipals_names (iterable): List of municipals for this entry

        Returns:

        """
        context = {
            "obj_identifier": obj_identifier,
            "resubmission": resubmission,
            "municipals_names": municipals_names,
            "EMAIL_REPLY_TO": EMAIL_REPLY_TO,
        }
        msg = render_to_string("email/resubmission/resubmission.html", context)
        user_mail_address = [resubmission.user.email]
        self.send(
            user_mail_address,
            _("Resubmission - {}").format(obj_identifier),
            msg
        )

