#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import annotations

import configparser
import json

from typing import Any
from typing import Dict
from typing import List

import boto3
import requests

from aws_xray_sdk.core import xray_recorder as xray

from sendgrid import SendGridAPIClient
from sendgrid.helpers.mail import Content
from sendgrid.helpers.mail import Email
from sendgrid.helpers.mail import Mail
from sendgrid.helpers.mail import MailSettings
from sendgrid.helpers.mail import Personalization
from sendgrid.helpers.mail import SandBoxMode

from iobot.client import IOBotClient
from psi_logger import logger
from psi_logger import log as _log
from psi_secrets import SecretsManager

from fivepillars.exceptions import FivePillarsEmptyMessageBodyException  # noqa: E501
from fivepillars.exceptions import FivePillarsEmptyToAddressException  # noqa: E501


@xray.capture()
class FivePillarsClient(IOBotClient):
    @xray.capture()
    @logger.log
    def __init__(self,
                 log = _log,
                 boto_session: boto3.session.Session = None,
                 http_session: requests.Session = None,
                 config: configparser.ConfigParser = None,
                 config_file: str = "iobot.ini",
                 secrets_manager: SecretsManager = None,
                 **kwargs) -> None:

        self.namespace = 'FivePillars'

        super().__init__(log=log,
                         boto_session=boto_session,
                         http_session=http_session,
                         config=config,
                         config_file=config_file,
                         secrets_manager=secrets_manager,
                         config_namespace=self.namespace,
                         **kwargs)

        self._endpoint = self.config[self.namespace]['base_url']
        self._secrets = self.client['secrets_manager']
        self._log = self.client['log']

    @xray.capture()
    @logger.log
    def compose_email(self,
                      sender: Dict[str, str] = None,
                      to: List['str'] = None,
                      cc: List['str'] = None,
                      bcc: List['str'] = None,
                      subject: str = "",
                      body: str = "",
                      html_body: str = "",
                      force: bool = False,
                      mock_sendgrid: bool = False) -> Mail:
        """Returns a sendgrid mail object decorated with personalizations
        >>> fp: FivePillarsClient = FivePillarsClient(log,boto_session,None,config_file='environments/unit.ini')

        >>> msg = fp.compose_email(sender={'name':'Foo Bar','address':'foo.bar@gmail.com'}, to=['johnt@me.com'], subject='Moo Bar', body='this is a line.\\nthis is another line.\\n')

        >>> msg.get()
        {'from': {'name': 'Foo Bar', 'email': 'foo.bar@gmail.com'}, 'subject': 'Moo Bar', 'personalizations': [{'to': [{'email': 'johnt@me.com'}]}], 'content': [{'type': 'text/plain', 'value': 'this is a line.\\nthis is another line.\\n'}]}

        >>> msg = fp.compose_email(sender={'name':'Foo Bar','address':'foo.bar@gmail.com'}, to=['johnt@me.com'], subject='Moo Bar', body='this is a line.\\nthis is another line.\\n', mock_sendgrid=True)

        >>> msg.get()
        {'from': {'name': 'Foo Bar', 'email': 'foo.bar@gmail.com'}, 'subject': 'Moo Bar', 'personalizations': [{'to': [{'email': 'johnt@me.com'}]}], 'content': [{'type': 'text/plain', 'value': 'this is a line.\\nthis is another line.\\n'}], 'mail_settings': {'sandbox_mode': {'enable': True}}}

        >>> msg = fp.compose_email(sender={'name':'Foo Bar','address':'no-reply@pearson.com'}, to=['john.torres@pearson.com'], subject='Moo Bar', body='this is a line.\\nthis is another line.\\n', html_body='Hello Mike,</br>\\n\\n        <p>\\n        A Vulnerabilities per Device (VPD) score has been calculated for </br>\\n        services supported by your team, "Cloud Delivery Engineering - Clinical" from 2021-01-26 </br>\\n        through 2021-02-25.</br>\\n        </p>\\n\\n        <div>\\n        <h3>How is VPD calculated?</h3>\\n        <p>\\n        VPD is calculated as [ Number of total vulnerabilities tagged by t_appid/ Number of Total Qualys Agents tagged by t_appid ]\\n        </p>\\n        </div>\\n\\n        <div class="tg-wrap"><table border="1" cellspacing="2" cellpadding="2">\\n        <thead>\\n          <tr>\\n            <th style="width:40%;">Services</th><th style="width:30%;">VPD</th><th style="width:30%;">%Change</th>\\n          </tr>\\n        </thead>\\n        <tbody>\\n        \\n         <tr><td style="width:40%; text-align:center;">Pearson Access_SVC00765</td><td style="width:30%; text-align:center;">   28.76</td><td style="width:30%; text-align:center;">   16.34%</td></tr>\\n         \\n        </tbody>\\n        </table></div>\\n\\n        <p>\\n        If you would like to give us feedback, please follow <a href=\\'https://forms.office.com/Pages/ResponsePage.aspx?id=1zTEjNCX00e1xRT-DjPjS0Y8xBKXOmlDhg8pLj3w38BUQkNOWFRHUFNHSkVPVkgwNUQzMUZaNE1INC4u\\'>here.</a>\\n        </p>\\n        ', mock_sendgrid=True)

        >>> msg.get()
        {'from': {'name': 'Foo Bar', 'email': 'no-reply@pearson.com'}, 'subject': 'Moo Bar', 'personalizations': [{'to': [{'email': 'john.torres@pearson.com'}]}], 'content': [{'type': 'text/plain', 'value': 'this is a line.\\nthis is another line.\\n'}, {'type': 'text/html', 'value': 'Hello Mike,</br>\\n\\n        <p>\\n        A Vulnerabilities per Device (VPD) score has been calculated for </br>\\n        services supported by your team, "Cloud Delivery Engineering - Clinical" from 2021-01-26 </br>\\n        through 2021-02-25.</br>\\n        </p>\\n\\n        <div>\\n        <h3>How is VPD calculated?</h3>\\n        <p>\\n        VPD is calculated as [ Number of total vulnerabilities tagged by t_appid/ Number of Total Qualys Agents tagged by t_appid ]\\n        </p>\\n        </div>\\n\\n        <div class="tg-wrap"><table border="1" cellspacing="2" cellpadding="2">\\n        <thead>\\n          <tr>\\n            <th style="width:40%;">Services</th><th style="width:30%;">VPD</th><th style="width:30%;">%Change</th>\\n          </tr>\\n        </thead>\\n        <tbody>\\n        \\n         <tr><td style="width:40%; text-align:center;">Pearson Access_SVC00765</td><td style="width:30%; text-align:center;">   28.76</td><td style="width:30%; text-align:center;">   16.34%</td></tr>\\n         \\n        </tbody>\\n        </table></div>\\n\\n        <p>\\n        If you would like to give us feedback, please follow <a href=\\'https://forms.office.com/Pages/ResponsePage.aspx?id=1zTEjNCX00e1xRT-DjPjS0Y8xBKXOmlDhg8pLj3w38BUQkNOWFRHUFNHSkVPVkgwNUQzMUZaNE1INC4u\\'>here.</a>\\n        </p>\\n        '}], 'mail_settings': {'sandbox_mode': {'enable': True}}}

        """

        log = self._log
        mail: Mail = Mail()
        personalization: Personalization = Personalization()

        if not sender:
            sender = {
              'name': 'MyScorecards',
              'address': 'no-reply@pearson.com'
            }

        if not body:
            if force:
                pass
            else:
                raise FivePillarsEmptyMessageBodyException('empty message body and "force" is False...')  # noqa: E501

        if not to:
            raise FivePillarsEmptyToAddressException('you need at least one address to send to...')  # noqa: E501

        for address in to:
            log.debug(f"adding TO recipient(s): {address}")
            personalization.add_to(Email(address))

        if cc:
            for address in cc:
                log.debug(f"adding CC recipient(s): {address}")
                personalization.add_cc(Email(address))

        if bcc:
            for address in bcc:
                log.debug(f"adding CC recipient(s): {address}")
                personalization.add_bcc(Email(address))

        mail.add_personalization(personalization)
        mail.from_email = Email(sender.get('address'), sender.get('name'))

        log.debug(f"Subject: {subject}")

        mail.subject = subject

        mail.add_content(Content("text/plain", body))

        if html_body:
            mail.add_content(Content("text/html", html_body))

        if mock_sendgrid:
            log.debug("activating sandbox mode")
            settings = MailSettings()
            settings.sandbox_mode = SandBoxMode(True)
            mail.mail_settings = settings

        return mail

    @xray.capture()
    @logger.log
    def send_email(self,
                   sendgrid_client: SendGridAPIClient = None,
                   mail: Mail = None) -> Any:

        """Send a email via sendgrid

        >>> fp: FivePillarsClient = FivePillarsClient(log,boto_session,None,config_file='environments/unit.ini')

        >>> msg = fp.compose_email(to=['john.torres@pearson.com'], subject='Mock Message', body='this is a line.\\nthis is another line.\\n', mock_sendgrid=True)

        >>> msg.get()
        {'from': {'name': 'MyScorecards', 'email': 'no-reply@pearson.com'}, 'subject': 'Mock Message', 'personalizations': [{'to': [{'email': 'john.torres@pearson.com'}]}], 'content': [{'type': 'text/plain', 'value': 'this is a line.\\nthis is another line.\\n'}], 'mail_settings': {'sandbox_mode': {'enable': True}}}

        >>> sg = sendgrid.SendGridAPIClient(testing.sendgrid_token())

        >>> response = fp.send_email(sendgrid_client=sg, mail=msg)

        >>> type(response)
        <class 'python_http_client.client.Response'>

        >>> response.status_code
        200

        >>> response.headers.__dict__.get('policy')
        Compat32()

        >>> response.body
        b''

        >>> msg = fp.compose_email(sender={'name':'MyScorecards','address':'no-reply@pearson.com'}, to=['john.torres@pearson.com'], subject='Mock VPD Report', body='this is a line.\\nthis is another line.\\n', html_body='Hello John,</br>\\n\\n        <p>\\n        A Vulnerabilities per Device (VPD) score has been calculated for </br>\\n        services supported by your team, "Cloud Delivery Engineering - Clinical" from 2021-01-26 </br>\\n        through 2021-02-25.</br>\\n        </p>\\n\\n        <div>\\n        <h3>How is VPD calculated?</h3>\\n        <p>\\n        VPD is calculated as [ Number of total vulnerabilities tagged by t_appid/ Number of Total Qualys Agents tagged by t_appid ]\\n        </p>\\n        </div>\\n\\n        <div class="tg-wrap"><table border="1" cellspacing="2" cellpadding="2">\\n        <thead>\\n          <tr>\\n            <th style="width:40%;">Services</th><th style="width:30%;">VPD</th><th style="width:30%;">%Change</th>\\n          </tr>\\n        </thead>\\n        <tbody>\\n        \\n         <tr><td style="width:40%; text-align:center;">Pearson Access_SVC00765</td><td style="width:30%; text-align:center;">   28.76</td><td style="width:30%; text-align:center;">   16.34%</td></tr>\\n         \\n        </tbody>\\n        </table></div>\\n\\n        <p>\\n        If you would like to give us feedback, please follow <a href=\\'https://forms.office.com/Pages/ResponsePage.aspx?id=1zTEjNCX00e1xRT-DjPjS0Y8xBKXOmlDhg8pLj3w38BUQkNOWFRHUFNHSkVPVkgwNUQzMUZaNE1INC4u\\'>here.</a>\\n        </p>\\n        ', mock_sendgrid=True)

        >>> response = fp.send_email(sendgrid_client=sg, mail=msg)

        """
        log = self._log
        log.debug(f"mail={json.dumps(mail.get())}")
        response = sendgrid_client.client.mail.send.post(request_body=mail.get())  # noqa: E501

        log.debug(f"response.code={response.status_code}")

        return response
