import json
import os
from smtplib import SMTPException

from django.conf import settings
from django.core.mail import send_mail
from django.utils.html import strip_tags
from requests import Session, Request
from zappa.asynchronous import task

from authenticate.models import EmailCall
from authenticate.models import SMSCall


def build_absolute_static_url(request):
    static_url = settings.STATIC_URL
    # if files are being served on the server itself, we need the domain from request object to construct an absolute URL
    # because email servers don't understand our relative paths
    if settings.STATIC_ROOT:
        static_url = request.build_absolute_uri(static_url)

    return static_url


def register_verification_code_email_content_builder(request, randnum, email):
    """
    This function is responsible for building html content to sending in email for the users whom registering to our site.
    it takes a random and an email, and build a html content with these and returns the content.
    """
    # using absolute path
    # refer to settings_production.py for more information
    with open(os.path.join(settings.BASE_DIR, 'authenticate/templates/register_email_verification_code.html'), 'r', encoding="utf8") as f:
        register_verification_code_html = f.read()
        content = register_verification_code_html.replace('__STATIC_URL__', build_absolute_static_url(request)).replace(
            '__REGISTER_VERIFICATION_CODE__',
            str(randnum)).replace(
            '__TARGET_USER_EMAIL__', email)

        return content


def reset_password_verification_code_email_content_builder(request, randnum, email):
    """
    This function is responsible for building html content to sending in email for the users whom changing or forgetting their passwords.
    it takes a randnum and an email, and build a html content with these and returns the content.
    """
    with open(os.path.join(settings.BASE_DIR, 'authenticate/templates/reset_password_email_verification_code.html'), 'r',
              encoding="utf8") as f:
        reset_password_verification_code_html = f.read()
        content = reset_password_verification_code_html.replace('__STATIC_URL__', build_absolute_static_url(request)).replace(
            '__RESET_PASSWORD_VERIFICATION_CODE__', str(randnum)).replace('__TARGET_USER_EMAIL__', email)
        return content


def invite_collaborator_email_content_builder(request, institute_name, caller_full_name):
    """
    This function is responsible for building html content to sending in email of inviting another user to a project.
    it takes a link and an email, and build a html content with these and returns the content.
    """
    with open(os.path.join(settings.BASE_DIR, 'collaborators/templates/invite_collaborator.html'), 'r', encoding="utf8") as f:
        invite_collaborator_html = f.read()
        content = invite_collaborator_html.replace('__STATIC_URL__', build_absolute_static_url(request)).replace(
            '__INSTITUTE_NAME__', institute_name).replace('__CALLER_FULL_NAME__', caller_full_name)
        return content


def correction_email_content_builder(request, examinee_name, exam_name, institute_name, score, max_positive_score, report_card_url):
    with open(os.path.join(settings.BASE_DIR, 'exam/templates/score_exam.html'), 'r', encoding="utf8") as f:
        correction_html = f.read()
        content = correction_html.replace('__STATIC_URL__', build_absolute_static_url(request)).replace(
            '__EXAMINEE_NAME__', examinee_name).replace('__EXAM_NAME__', exam_name).replace('__INSTITUTE_NAME__', institute_name).replace(
            '__SCORE__', score).replace('__MAX_POSITIVE_SCORE__', max_positive_score).replace('__REPORT_CARD_URL__', report_card_url)
        return content


@task
def send_html_email(content, email):
    """
    This function used for sending email to clients. it takes a content and an email
    as its arguments and send the content to that email
    """
    email_call = EmailCall(
        email=email,
        message=content,
        success=True
    )
    try:
        plain_message = strip_tags(content)
        r = send_mail('WikiAzma', plain_message, settings.SENDER_EMAIL_ADDRESS, [
            email], html_message=content)
        email_call.response = r
    except SMTPException as e:
        email_call.success = False
        email_call.response = e
    email_call.save()


def send_sms_with_pattern(to, patternt_params):
    if settings.SMS_USERNAME and settings.SMS_PASSWORD:
        s = Session()
        prepared_request = Request(
            'GET', 'https://ippanel.com/patterns/pattern', params=patternt_params).prepare()
        url = prepared_request.url
        url = url.replace(settings.SMS_USERNAME,
                          '*****').replace(settings.SMS_PASSWORD, '*****')
        try:
            response = s.send(prepared_request)
            if response.content.isdigit():
                success = True
            else:
                success = False
            response = response.content
        except:
            response = None
            success = False
        SMSCall.objects.create(
            phone=to,
            message=patternt_params['input_data'],
            url=url,
            pattern_code=patternt_params['pattern_code'],
            response=response,
            success=success
        )


def send_verification_code_sms(to, code):
    params = {
        'username': settings.SMS_USERNAME,
        'password': settings.SMS_PASSWORD,
        'from': settings.SMS_PHONE,
        'to': [to],
        'input_data': json.dumps({"verification_code": code}),
        'pattern_code': settings.VERIFICATION_PATTERN_CODE
    }
    send_sms_with_pattern(to, params)


# TODO 
def send_sms_invite(to, caller_name, institute_name):
    params = {
        'username': settings.SMS_USERNAME,
        'password': settings.SMS_PASSWORD,
        'from': settings.SMS_PHONE,
        'to': [to],
        'input_data': json.dumps({"caller_name": caller_name, "institute_name": institute_name}),
        'pattern_code': settings.INVITATION_PATTERN_CODE
    }
    send_sms_with_pattern(to, params)


def send_sms_correction(to, examinee_name, exam_name, institute_name, total_positive_score, max_positive_score, report_card_url):
    params = {
        'username': settings.SMS_USERNAME,
        'password': settings.SMS_PASSWORD,
        'from': settings.SMS_PHONE,
        'to': [to],
        'input_data': json.dumps({"examinee_name": examinee_name, "exam_name": exam_name, "institute_name": institute_name,
                                  "total_posetive_score": total_positive_score, "max_positive_score": max_positive_score,
                                  "report_card_url": report_card_url}),
        'pattern_code': settings.SCORE_PUBLISHED_NOTIFY_PATTERN_CODE
    }
    send_sms_with_pattern(to, params)
