import logging
import base64
from datetime import datetime
from rest_framework import views
from rest_framework.response import Response
import sendgrid
from django.conf import settings
from django.core.mail.backends.base import BaseEmailBackend
from python_http_client.exceptions import HTTPError, ForbiddenError
from sendgrid.helpers.mail import Mail, HtmlContent, Attachment
from data_ocean.permissions import MonitoringTokenPermission


logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)


class SendGridBadStatusError(Exception):
    pass


class EmailBackend(BaseEmailBackend):
    def __init__(self, fail_silently=False, **kwargs):
        super().__init__(fail_silently=fail_silently, **kwargs)
        self.api_key = settings.SENDGRID_API_KEY

    def send_messages(self, email_messages):
        sg = sendgrid.SendGridAPIClient(api_key=self.api_key)

        for email_message in email_messages:
            mail = Mail(
                from_email=email_message.from_email,
                to_emails=email_message.to,
                subject=email_message.subject,
                html_content=HtmlContent(email_message.body),
            )
            for attachment in email_message.attachments:
                mail.add_attachment(Attachment(
                    file_name=attachment[0],
                    file_content=base64.b64encode(attachment[1]).decode(),
                    file_type=attachment[2],
                ))
            try:
                response = sg.client.mail.send.post(request_body=mail.get())
                if response.status_code // 100 != 2:
                    error_message = (
                        f'Email "{email_message.subject}" was not sent to {email_message.to}. '
                        f'Status is {response.status_code}'
                    )
                    if self.fail_silently:
                        logger.error(error_message)
                    else:
                        raise SendGridBadStatusError(error_message)
            except HTTPError as error:
                if self.fail_silently:
                    if type(error) == ForbiddenError:
                        logger.exception(f'Email {email_message.subject} was not sent to {email_message.to} - {error.to_dict}')
                    else:
                        logger.exception(f'Email {email_message.subject} was not sent to {email_message.to} - {error}')
                else:
                    raise


class SendgridCreditsStatusView(views.APIView):
    permission_classes = [MonitoringTokenPermission, ]

    def get(self, request):
        sg = sendgrid.SendGridAPIClient(api_key=settings.SENDGRID_API_KEY)
        msg = ''
        try:
            response = sg.client.user.credits.get()
            # {
            # 'is_hard_limit': True,
            # 'last_reset': '2021-08-15',
            # 'next_reset': '2021-08-16',
            # 'overage': 0,
            # 'remain': 99,
            # 'reset_frequency': 'daily',
            # 'total': 100,
            # 'used': 1
            # }
            status = response.status_code
            if status == 200:
                remain = response.to_dict.get('remain')
                msg = 'OK' if remain > settings.SENDGRID_REMAIN_WARNING else 'WARNING'
                msg = f'Remain status is {msg}. (remain={remain})'
        except Exception as e:
            msg = f'{e}'
            status = 403

        return Response({"msg": msg}, status=status)


class SendgridBadMailStatusView(views.APIView):
    permission_classes = [MonitoringTokenPermission, ]

    def get(self, request):
        sg = sendgrid.SendGridAPIClient(api_key=settings.SENDGRID_API_KEY)
        msg = ''
        try:
            dt = datetime.utcnow()
            dt_start = int(datetime(dt.year, dt.month, dt.day, 0, 0).timestamp())
            params = {'start_time': dt_start, }
            response = sg.client._("suppression/bounces").get(query_params=params)
            # {
            # 'created': 1626358039,
            # 'email': 'kacocih238@nobitcoin.net',
            # 'reason': '550 5.1.1 <ka238@nobitcoin.net>: Recipient address rejected: User unknown ...,
            # 'status': '5.1.1'
            # }
            status = response.status_code
            if status == 200:
                count = response.to_dict.__len__()
                msg = 'OK' if not count else 'WARNING'
                msg = f'BadMail status is {msg}. (count={count})'
        except Exception as e:
            msg = f'{e}'
            status = 403

        return Response({"msg": msg}, status=status)
