# -*- coding: utf-8 -*-
# Code for Life
#
# Copyright (C) 2018, Ocado Innovation Limited
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# ADDITIONAL TERMS – Section 7 GNU General Public Licence
#
# This licence does not grant any right, title or interest in any “Ocado” logos,
# trade names or the trademark “Ocado” or any other trademarks or domain names
# owned by Ocado Innovation Limited or the Ocado group of companies or any other
# distinctive brand features of “Ocado” as may be secured from time to time. You
# must not distribute any modification of this program using the trademark
# “Ocado” or claim any affiliation or association with Ocado or its employees.
#
# You are not authorised to use the name Ocado (or any of its trade names) or
# the names of any author or contributor in advertising or for publicity purposes
# pertaining to the distribution of this program, without the prior written
# authorisation of Ocado.
#
# Any propagation, distribution or conveyance of this program must include this
# copyright notice and these terms. You must not misrepresent the origins of this
# program; modified versions of the program must be marked as such and not
# identified as the original program.
from datetime import timedelta
from uuid import uuid4

from django.core.mail import EmailMultiAlternatives
from django.template import loader
from django.utils import timezone
from requests import post
from requests.exceptions import RequestException

from common.email_messages import (
    emailChangeNotificationEmail,
    emailChangeVerificationEmail,
    emailVerificationNeededEmail,
)
from common.models import EmailVerification
from common import app_settings

NOTIFICATION_EMAIL = "Code For Life Notification <" + app_settings.EMAIL_ADDRESS + ">"
VERIFICATION_EMAIL = "Code For Life Verification <" + app_settings.EMAIL_ADDRESS + ">"
PASSWORD_RESET_EMAIL = (
    "Code For Life Password Reset <" + app_settings.EMAIL_ADDRESS + ">"
)
INVITE_FROM = "Code For Life Invitation <" + app_settings.EMAIL_ADDRESS + ">"


def send_email(
    sender,
    recipients,
    subject,
    text_content,
    html_content=None,
    plaintext_template="email.txt",
    html_template="email.html",
):
    # add in template for templates to message

    # setup templates
    plaintext = loader.get_template(plaintext_template)
    html = loader.get_template(html_template)
    plaintext_email_context = {"content": text_content}
    html_email_context = {"content": text_content}
    if html_content:
        html_email_context = {"content": html_content}

    # render templates
    plaintext_body = plaintext.render(plaintext_email_context)
    html_body = html.render(html_email_context)

    # make message using templates
    message = EmailMultiAlternatives(subject, plaintext_body, sender, recipients)
    message.attach_alternative(html_body, "text/html")

    message.send()


def generate_token(user, email="", preverified=False):
    return EmailVerification.objects.create(
        user=user,
        email=email,
        token=uuid4().hex[:30],
        expiry=timezone.now() + timedelta(hours=1),
        verified=preverified,
    )


def send_verification_email(request, user, new_email=None):
    """Send an email prompting the user to verify their email address."""

    if not new_email:  # verifying first email address
        user.email_verifications.all().delete()

        verification = generate_token(user)

        message = emailVerificationNeededEmail(request, verification.token)
        send_email(
            VERIFICATION_EMAIL, [user.email], message["subject"], message["message"]
        )

    else:  # verifying change of email address.
        verification = generate_token(user, new_email)

        message = emailChangeVerificationEmail(request, verification.token)
        send_email(
            VERIFICATION_EMAIL, [new_email], message["subject"], message["message"]
        )

        message = emailChangeNotificationEmail(request)
        send_email(
            VERIFICATION_EMAIL, [user.email], message["subject"], message["message"]
        )


def is_verified(user):
    """Check that a user has verified their email address."""
    verifications = user.email_verifications.filter(verified=True)
    return len(verifications) != 0


def add_to_dotmailer(first_name: str, last_name: str, email: str):
    try:
        add_contact_to_address_book(first_name, last_name, email)
    except RequestException:
        return


def add_contact_to_address_book(first_name, last_name, email):
    url = app_settings.DOTMAILER_URL
    body = {
        "email": email,
        "optInType": "VerifiedDouble",
        "emailType": "Html",
        "dataFields": [
            {"key": "FIRSTNAME", "value": first_name},
            {"key": "LASTNAME", "value": last_name},
            {"key": "FULLNAME", "value": f"{first_name} {last_name}"},
        ],
        "preferences": app_settings.DOTMAILER_DEFAULT_PREFERENCES,
    }
    post(
        url,
        json=body,
        auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD),
    )


def update_email(user, request, data):
    changing_email = False
    new_email = data["email"]
    if new_email != "" and new_email != user.email:
        # new email to set and verify
        changing_email = True
        send_verification_email(request, user, new_email)
    return changing_email, new_email
