#
# ============LICENSE_START==========================================
# org.onap.vvp/engagementmgr
# ===================================================================
# Copyright © 2017 AT&T Intellectual Property. All rights reserved.
# ===================================================================
#
# Unless otherwise specified, all software contained herein is licensed
# under the Apache License, Version 2.0 (the “License”);
# you may not use this software except in compliance with the License.
# You may obtain a copy of the License at
#
#             http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
#
# Unless otherwise specified, all documentation contained herein is licensed
# under the Creative Commons License, Attribution 4.0 Intl. (the “License”);
# you may not use this documentation except in compliance with the License.
# You may obtain a copy of the License at
#
#             https://creativecommons.org/licenses/by/4.0/
#
# Unless required by applicable law or agreed to in writing, documentation
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ============LICENSE_END============================================
#
# ECOMP is a trademark and service mark of AT&T Intellectual Property.
from datetime import datetime, timedelta
from uuid import uuid4
import bleach
from django.conf import settings
from django.template.loader import get_template
from engagementmanager import mail
from engagementmanager.models import Invitation, IceUserProfile, Engagement
from engagementmanager.utils.constants import Roles, Constants
from engagementmanager.utils.vvp_exceptions import VvpBadRequest
from engagementmanager.utils.validator import Validator, logEncoding
from engagementmanager.views_helper import getVfByEngUuid
from engagementmanager.service.logging_service import LoggingServiceFactory

logger = LoggingServiceFactory.get_logger()


def enforce_invitation_throttling(eng_uuid, invited_email,
                                  inviterUser, invitedUser):
    assert eng_uuid is not None
    assert invited_email is not None

    invitation = Invitation.objects.filter(
        engagement_uuid=eng_uuid, email=invited_email)
    if len(invitation) > 0:
        logger.warn(
            "Oops, looks like an invitation with " +
            "following details already exists: "
            + str(invitation))
        return False

    if (not invitedUser or (
        not invitedUser and invitedUser.role.name !=
            Roles.admin.name and invitedUser.role.name != Roles.el.name)):
        numOfInvitationinLast24H = Invitation.objects.filter(
            email=invited_email,
            create_time__gte=datetime.now() - timedelta(
                hours=24)).count()
        if numOfInvitationinLast24H >= 5:
            logger.warn(
                "Oops, looks like invited email (" + invited_email +
                ") which isn't EL nor admin has reached its "
                "max invitations (5) in the last 24 hours")
            return False

    if ((invitedUser and invitedUser.role.name == Roles.standard_user.name) or
            (invitedUser and invitedUser.role.name == Roles.admin_ro.name) or
            invitedUser is None):
        numOfInvitationinLast24H = Invitation.objects.filter(
            invited_by_user_uuid=inviterUser.uuid,
            create_time__gte=datetime.now() - timedelta(
                hours=24)).count()
        if numOfInvitationinLast24H >= 25:
            logger.warn(
                "Oops, looks like a standard-user/admin-readonly inviter "
                "(" + inviterUser.email + ") has reached its max invitations" +
                "(25) in the last 24 hours")
            return False
    return True


def generateInviteMail(data, inviterUser, invitedUser, is_contact_user):
    vf = getVfByEngUuid(data['eng_uuid'])
    if vf is not None:
        data['vf_name'] = vf.name
    else:
        data['vf_name'] = "-"
        logger.error("Couldn't fetch VF by engagement uuid=" +
                     logEncoding(data['eng_uuid']))

    body = get_template("{invite_template_dir}invite_mail_body.html".format(
        invite_template_dir=Constants.invite_template_dir))
    subject = get_template(
        "{invite_template_dir}invite_mail_subject.html".format(
            invite_template_dir=Constants.invite_template_dir))

    data['dashboard_link'] = str(settings.DOMAIN) + "/#/dashboard/"
    invitation = Invitation.objects.create(
        engagement_uuid=data['eng_uuid'],
        invited_by_user_uuid=inviterUser.uuid, email=data['email'],
        invitation_token=uuid4())

    if invitedUser is not None:
        data['invite_link'] = str(
            settings.DOMAIN) + "/#/login?invitation="\
            + str(invitation.invitation_token)
        data['instruction'] = "To accept this invitation, \
        please click this link:"
        logger.debug("Invited Contact with email " + data['email'] +
                     "already exist in the DB. Sending them an email "
                     "with link to login page. link=" + data[
            'invite_link'])
        if is_contact_user:
            logger.debug("Updating the Engagement with uuid=" + data[
                'eng_uuid'] + " to have this contact user: "
                + invitedUser.full_name)
            engObj = Engagement.objects.get(uuid=data['eng_uuid'])
            engObj.contact_user = invitedUser
            engObj.save()

    else:
        prefix = str(settings.DOMAIN) + "/#/signUp?invitation=" + \
            str(invitation.invitation_token) + "&email=" + data['email']
        suffix = ""
        if 'full_name' in data and data['full_name'] and \
                'phone_number' in data and data['phone_number']:
            suffix += "&full_name=" + \
                data['full_name'] + "&phone_number=" + data['phone_number']
            if data.get('company'):
                suffix += "&company=" + data['company']

        data['invite_link'] = prefix + suffix
        data['instruction'] = "To create an account and accept this " +\
            "invitation, please click this link:"

        if is_contact_user:
            data['invite_link'] += "&is_contact_user=true"
            logger.debug("The invite mail is sent to a contact "
                         "person (VF Contact or "
                         + Constants.service_provider_company_name
                         + " Sponsor)")

        logger.debug(
            "Invited Person doesn't exists, sending them an email " +
            "with link to signup. link=" + data['invite_link'])

    return body, subject, invitation


def inviteUserToSignUpOrLogin(inviterUser, data, is_contact_user):
    invitedUser = None

    Validator.validateEmail(data['email'])

    data['email'] = bleach.clean(data['email'], tags=['a', 'b'])
    rs = IceUserProfile.objects.filter(email=data['email'])

    if len(rs) > 0:
        invitedUser = IceUserProfile.objects.get(email=data['email'])

    is_invite_ok = enforce_invitation_throttling(
        data['eng_uuid'], data['email'], inviterUser, invitedUser)

    if not is_invite_ok:
        msg = "Invite couldn't be created"
        logger.error(msg)
        raise VvpBadRequest(msg)

    body, subject, invitation = generateInviteMail(
        data, inviterUser, invitedUser, is_contact_user)

    try:
        mail.sendMail(data['email'], data, body, subject)
    except Exception as e:
        logger.error(e)
        msg = "Something went wrong while trying to send mail to " + \
            data['email'] + " from " + inviterUser.email
        logger.error(msg)
        if invitation:
            logger.error("Rolling back the invitation (" +
                         invitation + ") due to problems in sending its mail")
            invitation.delete()
        raise Exception(msg)


def markInvitationAsAccepted(invitation_token):
    invitation = Invitation.objects.get(invitation_token=invitation_token)
    invitation.accepted = True
    invitation.save()
    logger.debug("Marking Invitation [" + str(invitation) + "] as accepted")
